// codeart.ru / Главная / Конструктор Форум

Конструктор rss подписка

Автор: Evgeny Sergeev

Давайте на секунду отвлечемся от задачи управления базой данных и поговорим о том, как интересно устроены некоторые вещи.

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

Если вдуматься, что такое лего? Разноцветные кубики небольшого размера. По отдельности ничего особенного из себя не представляющих. Но в умелых руках эти незамысловатые кубики превращаются в нечто красивое и невероятно сложное.

Самое интересное, что такая возможность достигается наличием всего пары свойств:

1. Малый размер.
Несмотря на то, что кубики бывают разного размера, можно с уверенностью сказать, что если разложить один большой кубик на более мелкие составляющие, то в итоге окажется, что все составные элементы абсолютно идентичны;
2. Возможность объединиться с любым другим элементом.
Если бы кубики нельзя было присоединять один к другому, то и собрать из них ничего дельного было бы невозможно.

Кстати 2-ое свойства мне кажется наиболее важным, сложность появляется именно там где возникает возможность взаимодействия. Сочетая разные вещи, получаем разные свойства. Это ли не замечательно?

А вот теперь вернемся к нашей задаче. Я уже обмолвился, что в основу всего я хочу положить простую таблицу и обернуть ее небольшим классом управления (это чтобы скрыть от разработчика работу с СУБД). Кстати, подумав, я решил, что правильнее ее будет называть не простой, а элементарной таблицей. Кроме свойства простоты еще добавим свойство взаимодействия и получаем своеобразный лего-кубик.

Давайте рассмотрим это на примере. Представим, что нам нужно сделать модуль новостей для сайта. Новости будут содержать следующую информацию: Дату, Название, Текст. Разбивать эти данные на три таблицы смысла не имеет, проще положить все в одну и назвать ее “Новости”, кроме трех перечисленных полей добавим еще поле “ID” и получится у нас таблица из четырех столбцов. Это на уровне Базы данных.

А на уровне языка программирования создадим три простых класса: Дата, Название, Текст и четвертый элементарный класс Новости, который, благодаря своему свойству “взаимодействие”, впитает их в себя. На псевдо языке это будет выглядеть примерно так:

Создать Дату();
Создать Название();
Создать Текст();

Создать Новости();
Новости->включить( Дату );
Новости->включить( Название );
Новости->включить( Текст );

Новости->создать_структуру();

Вроде все понятно кроме последней строчки. Что за “создать_структуру”? Смысл в том, что когда мы включили в новости три простых класса мы определили конфигурацию новости, и теперь только новость знает какие поля она содержит, а следовательно именно она должна создавать структуру базы данных. На псевдо языке это может выглядеть примерно так:

создать_структуру():
Определить начало SQL запроса: SQL_запрос = ‘CREATE TABLE НОВОСТИ(’;
Для каждого поля из новостей:
SQL_запрос += поле->получить_SQL_ для_создания_таблицы
Определить концовку SQL запроса: SQL_запрос += ‘PRIMARY KEY (id));’
Выполнить SQL_запрос
конец метода;

Таким образом, каждый класс (Дата, Текст, Название) содержит информацию о своей части построения запроса “CREATE” и выдает ее в методе создать структуру. Если мы исключим какой-то из этих классов класса “новости”, то и в создание структуры он не попадет.

Аналогичным образом строится обращение к данным, если нам нужно получить все новости, то делаем просто:

Новости->получить()

Если нам нужно получить, новости за определенную дату, то делаем так:

Новости->Дата->ограничить( сегодняшняя дата );
Новости->получить()

Таким образом сами Новости, не знаю, что их будут чем-то ограничивать, но составной класс Дата вносит в получение новостей свою часть SQL запроса и тем самым влияет на результат.

Добавление новости может выглядеть примерно вот так:

Новости->Дата->установить( сегодняшняя дата )
Новости->Заголовок->установить( Заголовок новости )
Новости->Текст->установить( Текст новости )

Новости->сохранить()

Опять же, каждый составной элемент отвечает только за свой кусочек SQL, который в последующем передает основному классу для исполнения.

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

Пока на этом все. Надеюсь, моя идея стала еще чуточку понятнее. А совсем понятной она станет, когда я выложу код.

  1. Мне кажется, или автор изобрел ORM?:)

  2. Александр, тут мэпинга данных нет, только построение запросов. Хотя никто не отрицает, что описанное выше есть некоторое подобие ORM.
    Так что твоя ирония мимо кассы как-то…

  3. Ну почему же. Не подобие, а точная копия. Просто в посте не указана ни одна ссылка на ORM, а если бы она была, то и 95% поста было бы ни к чему. Насчет мапинга, там где описано про “добавление новости” разве это не он самый?:)
    А вообще мне понравилось. И подняло настроение. Если уж изобретать опять велосипед, то с умным видом:)
    Спасибо.

  4. @Александр: true

    Не понимаю, чем это отличается от кейкового

    $category = $this->News->Category->find(array(’name’=>’Категория 1′));

    $this->News->save(array(
    ‘dat’=>date(’Y-m-d H:i:s’),
    ‘category_id’=>$category['Category']['id'],
    ‘title’=> ‘Заголовок новости’,
    ‘content’=>$content,
    )) or die(’Упс!’);

  5. Создать структуру проще заранее в БД (если хочется комформа, то через какой-то DBDesigner).
    А потом волшебное cake bake (удобная фича - консоль).

    Долгая работа с Zend Framework и CodeIgniter заставляют иногда придумывать велосипеды. :)

  6. Владимир Лучанинов, я уже говорил, что не знаком с CakePHP, поэтому не исключаю, что вещь в итоге получится идентичная. :-)

    “Долгая работа с Zend Framework и CodeIgniter заставляют иногда придумывать велосипеды. ”

    Вова, тут ты тоже скорее всего прав. То, что у меня получается нечто похожее на уже созданную хорошую схему (при том, что я об этой схеме ничего не знал) говорит о том, что я иду правильным путем. :-)

    Мир большой и придумать, что-то новое не возможно в принципе (ну или очень сложно как минимум). Поэтому не обижаюсь на высказывания в стиле “зачем придумывать велосипед” :-)

    “Создать структуру проще заранее в БД (если хочется комформа, то через какой-то DBDesigner).
    А потом волшебное cake bake (удобная фича - консоль).”

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

    Саша, даная заметка является продолжением предыдущей, там ссылка на ORM есть.

    “А вообще мне понравилось. И подняло настроение. Если уж изобретать опять велосипед, то с умным видом:)
    Спасибо”

    Ты ведешь себя так будто это ты создал доктрину. :-) Молодец конечно, но это отдает ребячеством. В любом случае, тебе тоже спасибо за комментарии.

  7. “Просто в посте не указана ни одна ссылка на ORM, а если бы она была, то и 95% поста было бы ни к чему.”

    Саша, ты явно не понимаешь, что такое ORM, хотя и пытаешься показать, что разбираешься в вопросе. Зачем эта показуха?

  8. В гадалку играешь?
    Я тоже:
    Вот ты про ORM явно только слышал, но не использовал. Поэтому этот пост у тебя и получился. Признал бы, а то глупо смотришься.

  9. Саша, давай ты просто приведешь ту ссылку которая заменит 95% процентов данного поста и будет описанием ORM?

    А что касается использования ORM, то не понятно, что значит “использовать ORM” ты имеешь в виду какую то конкретную реализацию?
    Если в общем, то, например, с паттерном ActiveRecord я довольно часто сталкиваюсь. В том же cakePHP, судя по всему, как раз он и реализован.

  10. @Евгений:

    > Мне нужно чтобы можно было структуру генерировать на лету
    Зачем? Объясни задачу, может комментаторы подскажут как решить.

    > Опять же я вообще не должен знать, где у меня хранятся данные в базе или в файлах на диске.
    В Cake Model всё равно откуда брать данные. Там есть по умолчанию поддержка известных баз данных, но при желании за час можно написать поддержку файлов в нужном формате вместо базы данных.

  11. Вова, насчет CakePHP ты меня уже заинтересовал. Я вчера немного посмотрел документацию, посмотрел твой блог. Пока к однозначному мнению не пришел. Например, я еще не разобрался как кейк работает со сложными структурами данных, где нужно в один запрос увязать несколько таблиц.

    Насчет задачи генерации структуры на лету. Я размышлял таким образом, допустим у меня есть готовый модуль, возьмем для примера все те же новости. В определенный момент времени заказчик мне говорит, все хорошо, но мне нужно, чтобы новости бились по категориям (естественно все добавленные на данный момент новости, по умолчанию относятся к определенной категории). Такую задачу я решаю так:
    В сам модуль новости я не лезу. Ибо это базовый модуль и трогать его нет смысла. Вместо этого в конструкторе контролера новостей пишу следующие три строчки:

    $this->News->register( ‘Category’, ‘Category’, ‘Categories’);
    $this->News->Category->inResult();
    $this->News->update();

    Первая строчка добавляет в структуру новостей категорию, вторая заставляет по умолчанию в результат запроса к БД вставить название категории. Третья строчка производит обновление структуры базы данных.

    Теперь остается только указать в шаблоне новостей где выводить название категории. Форма по добавлению новости строится автоматически на основе структуры.

    Что делать если вдруг заказчик захотел древовидную структуру категории? Нет проблем, пишем так:

    $this->News->register( ‘Category’, ‘Category’, ‘Categories’);
    $this->News->Category->register(’CategoryID’, ‘Parent’);
    $this->News->Category->inResult();
    $this->News->update();

    Функция register принимает на вход имя элементарной таблиц в данном случае категория, второй параметр это псевдоним по которому будет идти обращение, третий это название таблицы в БД, если он не указан, то поле создается в той же таблице. В данном случае для “Parent” создается поле в той же таблице.

    Плюсы такого подхода следующие:

    1. Я не лезу в код модуля и саму БД
    2. Работаю только с Контролером и шаблонами (для меня это удобно)
    3. Могу оперативно реагировать на “хотелки” заказчика.

    В этом и есть смысл генерации “на лету” изначально у меня не было модуля с категориями, но я его сгенерировал по ходу дела.

    Надеюсь, что понятно объяснил. :-)

  12. Расскажу как я решал бы эту же задачу. Получается тоже быстро.

    1. Надо добавить категории.
    Создаю таблицу categories, cake bake создаёт модель.
    В таблице news добавляю поле category_id, добавляю в модель новостей
    var $belongsTo = array(
    ‘Category’ => array(’className’ => ‘Category’, ‘foreignKey’ => ‘category_id’)
    );

    2. Нужна древовидная структура.
    В таблице categories добавляю поле parent_id, в модели категорий
    var $belongsTo = array(
    ‘Parent’ => array(’className’ => ‘Category’,'foreignKey’ => ‘parent_id’),
    );
    var $actsAs = array(’TreeOrdered’=>array()); // TreeOrdered - это мой модуль, но есть похожий встроенный

    Работать только с контроллером и шаблонами считается в Cake - “Bad cake”. Там хорошей практикой считается: 50% - модели, 30% - виды (шаблоны), 20% - контроллеры.
    А у тебя модели и контроллеры совмещены. Паттерн MVC объясняет, почему это не очень хорошо в долгосрочной перспективе.

  13. Вовы и опять ты прав :-) выносить в контроллер код, который явно предназначен для модуля - плохой стиль. В описанном мной случае логичнее было-бы использовать наследование, а не изврат с контроллером.
    Но при этом идея создавать структуру на лету мне всеравно импонирует. Не хочу я сначала создавать структуру базы, потом писать код для работы с ней. :-) Хочу писать код, который сам создает структуру и сам знает как с ней работать, а я только говорю, что вот в этом модуле будет храниться информация об Авторе, Дате публикации и содержании новости, а в вот в этом модуле будет содержаться информация о пользователях.

    В идеале у меня должен быть набор элементарных классов, каждый из которых представляет из себя некую сущность, допустим класс ФИО может в модуле выступать в роли Автора, Пользователя, Комментатора. Но независимо от смысла везде будет использоваться Фамилия Имя и Отчество. Или класс Дата может выступать в роли “даты создания”, “даты модификации”, “даты последнего посещения”, но опять же везде это будет дата и для нее будут справедливы действия с датами.

    Зачем создавать в базе поле “Дата создания”, потом в модуле писать код для обработки этой даты, если на 90% этот код будет похож на код написанный пятью минутами ранее для “даты последней модификации”? Или все же в Кейке есть возможность один раз написать код для обработки дат, а потом подсовывать его в разном контексте?

    Я так понял, что Cake предлагает для каждой таблицы в базе создать свою модель? Или это на откуп разработчика остается?

    Отношение 50%-30%-20% - это, насколько я понял, при разработке нового модуля? Но очень часто сталкиваешься с необходимостью повторно использовать готовые модули, тогда модель почти не меняется, а вот контроллер может изменяться значительно. Что Cake говорит на эту тему?

  14. Да, для каждой таблицы создаётся отдельная модель. В этом больше преимуществ, чем недостатков.

    Если несколько моделей (в одном или разных проектах) используют общую функциональность, то считается хорошим тоном выносить их в Behavior. Я описал это в php.southpark.com.ua/2007/10/20/kak-sozdat-behavior-dlya-cakephp/.

    Класс “Дата” - это, по-моему, уже слишком абстрактно для большинства программ на PHP. В Java я бы это понял, там любят создавать класс Dollar (часто используется в примерах). Если пользоваться удобными инструментами (я люблю Navicat), то менять структуру базы данных напрямую намного проще.

  15. Владимир Лучанинов, спасибо за советы. Буду потихоньку разбираться с CakePHP, возможно потом и пересяду на него.

Leave a Reply

« Требования к системе управления данными проекта Красота спасет мир, а ремонт доканает меня »

 

купить радуга тв | Композитные бассейны Admiral: строительство бассейнов. | керамзит с доставкой сайт .