Как стать автором
Обновить

Комментарии 47

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

В особо интересных случаях модель может использовать даже не одну таблицу и не один экземпляр Zend_Db_Table (хотя мне такая архитектура и кажется странной).
Вы неправильно меня поняли!

Не надо модели наследовать код от тейбла. Просто ваш DynFinder будет расширять Zend_Db_Table и в последствии заменять его. Тогда не нужен код в конструкторе, а _call превратится в
public function __call($name, $arguments)
{
return call_user_func_array(array($this->getTable(), $name), $arguments);
}

Правда в итоге она наследует все ф-ции таблицы (как и в вашем случае), но можно поставить проверку на то что имя ф-ции начинается на get…

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

Мысль такая в голову, конечно, пориходила.
*«как правило» — ох уж эти опечатки :)
А картинка к статье лукавая… в актуальном Zend Framework тоже самое делается проще:
public function getTagById($id)
{
  $table = $this->getTable();
  $res = $table->getAdapter()->fetchRow(
    $table->select()
          ->columns('tag')
          ->where('id = ?', $id)
  );
ну а если ещё и предметную область проанализировать, то этот метод бы выглядел так:
public function getTagById($id)
{
  $table = $this->getTable();
  return $table->getAdapter()->fetchOne(
    $table->select()
          ->columns('tag')
          ->where('id = ?', $id)
  );
}

или даже может так:
public function getTagById($id)
{
  $row = $this->getTable()->find($id)->current();
  return $row ? $row->tag : null;
}
А тепрь, допустим, мы ищем не по Primary key…
->getADapter() тоже не обязательно)
Исходный код достаточно старый, из проекта накотором я учился ZF. Тогда разобраться отдельно с кавычками было также актуально :)
НЛО прилетело и опубликовало эту надпись здесь
Я, к примеру, так делал со многими редакторами — просто менял у них цвета текста, цвет выделенного текста, ключевых слова, скобок, фона и т.д., которые обычно можно выставить в настройках редактора. Такое проделывал с gEdit, с MS Visiaul Studio и со всякими другими.
У меня на тёмном фоне видно чётче и визуальная навигация быстрее, но, по идее, быстрее устают глаза.
NetBeans, тема City Lights, местами доправленная до собственных нужд
Хм, а вообще такой механизм поддерживается в ZF и сделан аналогично rails'овому
Вы можете также запрашивать строки из родительской таблицы, используя «магический метод». Zend_Db_Table_Row_Abstract вызывает метод: findParentRow('', ''), если вы вызываете метод объекта Row, соответствующий одному из следующих шаблонов:

*

$row->findParent([Zend_Db_Table_Select $select])
*

$row->findParentBy([Zend_Db_Table_Select $select])


На сколько помню, есть так же и findBy
А если что-то не неализовано, то нужный класс всегда можно расширить и дать сообществу.
хабрапарсер порезал код… в общем, есть такие магические методы как getParent[TableClass]By[Something] и, get[TableClass]By[Something]

например, имеем статью $article и можем получить все её теги: $article->getParentTags();
Правильно, но в роли something должно быть некое rule, описанное в $_refrence_map? Или можно обойтись?

И, потом, допустим ли поиск по нескольким полям? С условиями And или Or?

Да и мне, собственно, и не надо получать данные от связанной модели, мне надо получить данные по данной конкретной модели, причем скорее по нескольким полям (т.к. в простейших случаях — да, find по primary keys вполне себе ищет).

Если же речь идет о самостоятельно созданном Select — так собственно мой класс для генерации этого Select главным образом и предназначен. Как далее его использовать (find… vs. getAll...) — ваше право.
>Или можно обойтись?
Вроде как нельзя

>И, потом, допустим ли поиск по нескольким полям?
Ну да, тут проигрывает rails, но когда нужен поиск по нескольким полям, кто мешает просто указать нужные where() ?)

>мне, собственно, и не надо…
Не оправдывайтесь) Ваше решение очень даже хорошо, просто всегда нужно понимать где что следует использовать в конкретной ситуации… Если у вас описаны все модели как наследники Zend_Db_Table_Abstract, прописаны все отношения, то думаю таки лучше использовать то, что уже реализовано в ZF…
Ну так, по сути, я и писал генератор этих самых where вне контекста отношений и поиска только по ним :). Логин, пароль и уникальных хэш юзера могут сами по себе ни к чему не относиться (и свойство этих колонок будет простым index в таблице). В то время как числовой id юзера — таки да.

Словом, решение задумывалось преимущественно не под поля, описанные в отношениях между таблицами, а, скорее, под выборки очень произвольных данных из таблицы. А пример на картинке — только пример :).

>и свойство этих колонок будет простым index в таблице

Речь шла об индексе по колонке, конечно. Ох уж этот конец дня.
Я использую такой вариант.
в Table_Abstract определен метод selecBy($field, $value), который возвращает такой же select.
А сам класс Db_Table_Select расширен методами fetchAll(), fetchRow(), getPaginator(), count(), max(), random() и т.п.

Пример использования.
$this->view->paginator = $table->selectBy('category', 'name')->getPaginator($page, $per_page);

Такой подход, ИМХО, наиболее гибкий. Фактически мы можем вызывать selectBy столько раз сколько нам нужно, а на выходе получать строку, набор, кол-во, paginator и т.п.
Хотя в контроллерах ничего сложнее selectBy (один вызов) лучше не делать. Для этого нужно писать соотвествующие методы в таблицах и покрывать их тестами.
Речь идет о вашем наследнике Zend_Db_Table (Table_Abstract)?
Да, у меня есть небольшая надстройка над Zend имеющая префикс Ext.
В исходнике, в строке 337 синтаксическая ошибка: не закрыта скобка

функционал _camelCase2underscore($column), если я не ошибаюсь, уже есть в Zend/Filter
и ещё: странно выглядят конструкции

Да что он сам отправляет-то?

странно выглядят конструкции $this->$columnParseCallback при том, что public $columnParseCallback = array();
Также надо быть внимательным: есть тонкий момент с кэшированием.
Как известно, Zend_Db_Table умеет кэшировать метадату.
Так вот если на живой сайт опубликовать одновременно новый столбец в БД и код на основе этого модуля, использующий этот столбец — будет 187: unset($args['options']['order'][$key]); — сортировка работать не будет до сброса кэша.
Спасибо за замечание, задумывался над этим во время разработки.

Будем надеяться, что на живых серверах при апгреде БД рзаработчики бдут помнить о необходимости и сбросить кэш.
В статье есть на эту тему:
===
Также есть вариант внешнего разбора имени метода (вместо внутреннего _camelCase2underscore() ). Т.е. ваши правила именования колонок в таблицах и в именах метода для файндера будут отличаться. В таком случае где-то до вызова метода __call надо определить свойство $this->columnParseCallback в виде callback (как для call_user_func()), в котором вы и зададите внешнюю функцию-парсер вашего имени метода.
===
ну я примерно так и понял, не понял только почему
$this->$columnParseCallback
а не
$this->columnParseCallback
упс, спасибо, сейчас же исправлю
Спасибо, исправил
меня всегда удивляло, почему за два года развития в Zend Framework нет хотя бы какой-нибудь реализации Active Record. каждый раз нужно изобретать велосипед, вместо того, чтобы получить все из коробки, как допустим в Yii framework.
Я думаю, этот вопрос скорее к идеологам ZF: где-то в документации даже было, что AR каждый может разработать по-своему, основываясь на предоставленных ZF классах. Насколько я вижу — преимущественно на базе Zend_Db_Table_Row и Zend_Db_Table_Rowset.
А вас никогда не удивляло то что можно с лёгкостью прикрутить Doctrine к ZF?
а зачем если есть Zend_Db и Database Table Gateway Pattern?
Doctrine это альтернатива вышеназванным компонентам. Сторонники Active Record прикручивают Doctrine, любители Database Table Gateway Pattern используют нативный компонент, ну а для маленьких проектов можно вообще только PDO использовать. Вооо какой выбор!

Я лично использую Doctrine, так как для Zend_Db нужно писать много кода ручками, а Doctrine сама всё генерирует. Хотя конечно тяжела гадина, +7-20mb каждый php процесс отжирает, благо сервер мощный ксеон. Обещали ко второй версии исправить ситуацию.
для Zend_Db можно один раза написать и наследоваться от своего класса постоянно, поэтому я не вижу у доктрин преимуществ перед зенд диби. тут дело вкуса.
Тут дело паттерна. Кому нравится паттерн DTGP, а кому AR.
я впринципе это и имел ввиду=)
orm != active record
active record = row gateway (Zend_Db_Table_Row) + бизнес логика. www.design-pattern.ru/patterns/active-record.html

Так что в зенде с active record все в порядке, а вот orm функционала нет и это действительно бывает неудобно. Правда в zf2 нас ждет переход на doctrine2, но это конец 2010 года, если повезет.
Да кстати, протупил выше. Имелся ввиду ORM.
Насчёт перехода на doctrine, уже вроде отличный адаптер есть, и для пагинации в том числе.
Мне такое не очень нравится, но если бы ты сделал генерацию классов с докблоками и т. п. было бы здорово. И положи код на www.zfsnippets.com/
А как насчет Code Completion? IMHO, здесь время девелопера никак не экономится, т.к. надо помнить некие правила и соглашения о том, как и что.

Именно по этой же причине я крайне негативно отношусь к helper`ам во View, которые по тем же принципам устроены.

Вот когда авторы ZF добавят к документации класса @magic`и, тогда можно считать, что штука время экономит.
в Zend Studio интеллисенс в вьюшках работает
если я не ошибаюсь, то во второй Доктрине от этого отказались.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории