За последние 24 часа нас посетили 118346 программистов и 8024 робота. Сейчас ищет 1561 программист ...

Проектирую (ООП) галерею исходя из БД

Тема в разделе "PHP для новичков", создана пользователем jsm01, 15 мар 2013.

  1. jsm01

    jsm01 Активный пользователь

    С нами с:
    15 мар 2013
    Сообщения:
    5
    Симпатии:
    0
    Подскажите, как правильно спроектировать фотогалерею, исходя из имеющейся БД? Исходные вводные - есть 2 таблички, 1-я называется cats, разделы, поля id int4 и name varchar(250). Вторая - images, поля - id int4, filename varchar(250), category int4 (здесь ссылка на cats - FK cats(id) ).

    Впрямую пишу вот так:
    Код (Text):
    1.  
    2. class category {
    3.     private $id;
    4.     private $name;
    5. ... геттеры/сеттеры
    6. }
    7.  
    8. class image {
    9.     private $id;
    10.     private $filename;
    11.     private $category;
    12. ... геттеры/сеттеры
    13. }
    И сразу затык.
    1) как лучше организовать загрузку/инициализацию объекта из БД? Как мне увязать (грамотно) например PDO и первый класс category? Какой-то шаблон надо применить, или как?
    2) Как повязать category и image? Варианты навскидку - а) хранить в $category соответствующий объект ; б) переименовать поля в классе category и унаследовать от него image ; в) какой-то типовой прием?

    Пытаюсь разобраться с ООД, но от книжек ООП уже реально, голова кругом. Хочется чтоб как в best practices, а умеется пока только процедурный код :)
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.223
    Адрес:
    там-сям
    геттеры/сеттеры это из мира Java.
    связь с PDO может быть очень простой - там где надо, просто обращайся к PDO )))
    не пытайся родить еще один мега-универсальный ORM, говно получится
    класс Категории точно нужен? я бы ограничился просто атрибутом категория в классе Изображение.
    тебе понадобится какая-то Коллекция изображений, выбор по категории будет одним из вариантов фильтра.
    хочешь красивости и ООПности - сделай Коллекцию как воплощение интерфейса Iterator.
     
  3. jsm01

    jsm01 Активный пользователь

    С нами с:
    15 мар 2013
    Сообщения:
    5
    Симпатии:
    0
    Спасибо за советы, насчет итератора - так и сделаю. Про откусить категорию - там в реале еще есть поле parent, которое собственно дает доп.табличке смысл.
     
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.223
    Адрес:
    там-сям
    Раньше, когда программисты растили бороды, считалось что наследование это круто. Сейчас все сходятся на том, что интерфейсы это хорошо, а наследование привносит ненужную сложность.

    Попробуй сделать так: опиши что должно происходить, только методы, переменные отложи на потом. Методы сгруппируй в интерфейсы, например:
    МенеджерФайлов умеет аплодить, отдавать и удалять файлы.
    МенеджерКартинок умеет создавать копии других размеров, накладывать вотермарк.
    КоллекцияКартинок создает коллекции по заданным условиям и т.д
    Накопится пяток таких групп по функциям. Потом возможно ты воплотишь МенеджерФайлов и МенеджерКартинок в одном классе Изображение, а возможно в разных. В любом случае тебе удобно будет описывать передаваемый куда-то объект как соответствующий тому или иному интерфейсу.

    Скорее всего это закончится очередным недоделанным хламом, зато ты прокачаешь своё абстрактное мышление :)
     
  5. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.333
    Симпатии:
    1.753
    Ох уж эта ветреная девка Мода!..
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.129
    Симпатии:
    1.223
    Адрес:
    там-сям
    Ветреными бывают дамы, а девки непотребными :) Модно расслаблять связи: гулящие легкомысленные классы.
     
  7. Your

    Your Старожил

    С нами с:
    2 июл 2011
    Сообщения:
    4.068
    Симпатии:
    7
    Патриарх великий =)


    Что это будет то? Оо.
     
  8. jsm01

    jsm01 Активный пользователь

    С нами с:
    15 мар 2013
    Сообщения:
    5
    Симпатии:
    0
    Пример чисто умозрительный пока. Разбираюсь в ООП. Процедурный код на пыхе пишу с 2001, есть в т.ч. свой движок для магазинов (проектировался в свое время с оглядкой на osCommerce 2.1), но что-то ветреная мода стала все больше ООП (считал такой код сильно избыточным для разработчика-одиночки, но пора бы уже перестать от него шарахаться :)

    Сейчас на ряде сайтов пришел к простейшей CMS, которая меня не устраивает именно тем, что ООП (как мне кажется) может полечить - наращиваемостью ядра и легкостью ведения разных веток, допиленных для разных клиентов. Изучаю Зандстру, но что-то мозг подзаплыл :)

    Добавлено спустя 3 минуты 6 секунд:
    Код для категорий CMS, вместе с хранилищем. Пока получается вот такое чудище:

    Код (Text):
    1.  
    2. class Category {
    3.  
    4.     private $id = NULL;
    5.     private $name = NULL;
    6.     private $parent = "NULL";
    7.     private $updated = 0;
    8.  
    9.            
    10.     function __construct($myid = NULL, $myname = NULL, $myparent = NULL) {
    11.                    
    12.         if (isset($myid)) {
    13.             $this->id = $myid;
    14.         }
    15.         if (isset($myname)) {
    16.             $this->name = $myname;
    17.         }
    18.         if (isset($myparent)) {
    19.             $this->parent = $myparent;
    20.         }
    21.     }
    22.  
    23.     function getId() {
    24.         return $this->id;
    25.     }
    26.  
    27.     function getName() {
    28.         return $this->name;
    29.     }
    30.  
    31.     function setName($in) {
    32.         if (!is_null($this->name) || $this->name != $in) {
    33.             $this->updated = 1;
    34.         }
    35.         $this->name = $in;
    36.     }
    37.  
    38.     function getParent() {
    39.         return $this->parent;
    40.     }
    41.  
    42.     function setParent($in) {
    43.         if (!is_null($this->parent) || $this->parent != $in) {
    44.             $this->updated = 1;
    45.         }
    46.         $this->parent = $in;
    47.     }
    48.  
    49.     function isUpdated() {
    50.         return ($this->updated);
    51.     }
    52.  
    53.     function __destruct() {
    54.         echo "Destructor for '{$this->id}' '{$this->name}' fired<br />\n";
    55.     }
    56.  
    57.     function __toString() {
    58.         return "Object Category({$this->id}, '{$this->name}', {$this->parent}, {$this->updated})";
    59.     }
    60.  
    61. }
    62.  
    63. class CategoryCollection implements Iterator {
    64.  
    65.     private $var = array();
    66.  
    67.     public function __construct($array) {
    68.         if (is_array($array)) {
    69.             $this->var = $array;
    70.         }
    71.     }
    72.  
    73.     public function rewind() {
    74.         reset($this->var);
    75.     }
    76.  
    77.     public function current() {
    78.         $var = current($this->var);
    79.         return $var;
    80.     }
    81.  
    82.     public function key() {
    83.         $var = key($this->var);
    84.         return $var;
    85.     }
    86.  
    87.     public function next() {
    88.         $var = next($this->var);
    89.         return $var;
    90.     }
    91.  
    92.     public function valid() {
    93.         $key = key($this->var);
    94.         $var = ($key !== NULL && $key !== FALSE);
    95.         return $var;
    96.     }
    97.  
    98. }
    Все еще думаю, как замапить его на базу.
     
  9. jsm01

    jsm01 Активный пользователь

    С нами с:
    15 мар 2013
    Сообщения:
    5
    Симпатии:
    0
    Реконструировал все.
    index.php
    Код (Text):
    1.  
    2. spl_autoload_register(function ($class){
    3.     if(!file_exists($class.'.php')) {
    4.         $class = strtolower($class);
    5.     }
    6.     include $class.'.php';
    7. });
    8.  
    9. abstract class CMSCollection implements Iterator {
    10.     use varIterator;
    11.    
    12.     protected $var = array();
    13.  
    14.     public function __construct($array) {
    15.         if (is_array($array)) {
    16.             $this->var = $array;
    17.         }
    18.     }
    19. }
    20.  
    21. class ItemCollection extends CMSCollection {
    22.     function add(Item $i) {
    23.         $this->var[] = $i;
    24.     }
    25. }
    26.  
    27. class ItemDbLink {
    28.     static function getById($id, PDO $db) {
    29.         $res = $db->query("SELECT * FROM items WHERE id=$id");
    30.         if($data = $res->fetch(PDO::FETCH_ASSOC)) {
    31.             return new Item($data);
    32.         }
    33.         else {
    34.             throw new Exception('Cannot find item with id='.$id);
    35.         }
    36.     }
    37. }
    38.  
    39.  
    40. $conf = new Config();
    41. echo $conf['db']['dsn'],'<br />';
    42. $db = new PDO($conf['db']['dsn'], $conf['db']['login'], $conf['db']['password']);
    43.  
    44. try {
    45.     $getdata = ItemDbLink::getById(1, $db);  
    46.     foreach ($getdata as $key=>$val) {
    47.         echo $key, "-", ($key!='type')?$val:ItemTypes::getDescription($val), "<br />\n";
    48.     }
    49. }
    50.  catch (Exception $e) {
    51.      echo "Fired: ", $e->getMessage();
    52.  }
    config.php (по мотивам TodoList примера из Netbeans)
    Код (Text):
    1.  
    2. class Config implements ArrayAccess {
    3.     private $data = null;
    4.    
    5.     public function __construct() {
    6.         $this->data = parse_ini_file('config.ini', true);
    7.     }
    8.     public function offsetSet($offset, $value) {
    9.         throw new Exception('config is read only');
    10.     }
    11.     public function offsetExists($offset) {
    12.         return isset($this->data[$offset]);
    13.     }
    14.     public function offsetUnset($offset) {
    15.         throw new Exception('config is read only');
    16.     }
    17.     public function offsetGet($offset) {
    18.         return isset($this->data[$offset]) ? $this->data[$offset] : null;
    19.     }
    20. }
    item.php:
    Код (Text):
    1.  
    2. class Item implements Iterator {
    3.     use varIterator;
    4.    
    5.     private $var;
    6.     private $updated = 0;
    7.    
    8.     public function __construct(array $var = NULL) {
    9.         if(isset($var) && is_array($var)) {
    10.             $this->var = $var;
    11.         }
    12.         else {
    13.             $this->var = array();
    14.         }
    15.         if(!key_exists('parent', $this->var)) {
    16.             $this->var['parent'] = 'NULL';
    17.         }
    18.     }
    19.     public function __get($k) {
    20.         return $this->var[$k];
    21.     }
    22.     public function __set($k, $v) {
    23.         if($k != 'id') {
    24.             $this->var[$k]=$v;
    25.         }
    26.         else {
    27.             throw new Exception('Cannot set `id` field');
    28.         }
    29.         $this->updated = 1;
    30.     }
    31.     public function __isset($k) {
    32.         return key_exists($k, $this->var);
    33.     }
    34.     public function isUpdated() {
    35.         return $this->updated;
    36.     }
    37. }
    itemtypes.php:
    Код (Text):
    1.  
    2. abstract class ItemTypes {
    3.     const TEXT = 1;
    4.     const NEWS = 2;
    5.     const SYSTEM = 4;
    6.    
    7.     /**
    8.      * Returns type description
    9.      * @param int $type item type (number)
    10.      * @return string description
    11.      */
    12.     static function getDescription($type) {
    13.         $res = '';
    14.         switch ($type) {
    15.             case ItemTypes::TEXT:
    16.                 $res = 'Тексты';
    17.                 break;
    18.             case ItemTypes::NEWS:
    19.                 $res = 'Новости';
    20.                 break;
    21.             case ItemTypes::SYSTEM:
    22.                 $res = 'Служебные страницы';
    23.                 break;
    24.             default:
    25.                 $res = 'не определено';
    26.                 break;
    27.         }
    28.         return $res;
    29.     }
    30. }
    и наконец трейты - varIterator.php
    Код (Text):
    1.  
    2. trait varIterator {
    3.     public function rewind() {
    4.         reset($this->var);
    5.     }
    6.  
    7.     public function current() {
    8.         $var = current($this->var);
    9.         return $var;
    10.     }
    11.  
    12.     public function key() {
    13.         $var = key($this->var);
    14.         return $var;
    15.     }
    16.  
    17.     public function next() {
    18.         $var = next($this->var);
    19.         return $var;
    20.     }
    21.  
    22.     public function valid() {
    23.         $key = key($this->var);
    24.         $var = ($key !== NULL && $key !== FALSE);
    25.         return $var;
    26.     }    
    27. }
    С хренову душу функциональности, а кода уже пачка. Одна надежда, что управляемость улучшится. И да, конфигурация ini-шником и сведение всей работы с БД в пару классов - фенечка очень соблазнительная.

    По магазину например для оптимизации я держу список всех SQL запросов с указанием, какой в каком файле и какой строке содержится - очень выморочно было оптимизировать скорость работы.