Есть новости и категории. Мне нужно создать API для получения этих новостей. Не могу придумать, как это лучше сделать. Пока есть такой вариант: PHP: <? class News: getNews(array or string $fields, int $from, int $length, str $orderBy, str $orderType) /* возвращает в виде массива список новостей кол-вом $length начиная с $from отсортированных в соотв. с условиями. Из всех категорий. все аргументы - опциональны (по умолчанию будет что-то). $fields - поля, которые нужно вернуть (типа id, content, content_short, link_to_full) */ getNewsById(int $id, array or str $fields) // возвращает одну новость по ее IDшнику в базе. Привет, кэп! getNewsByCategory(int $category_id, array or string $fields, int $from, int $length, str $orderBy, str $orderType) // тоже самое, что и getNews, но только из одной категории. // ... /* как-то мне это не нравится. Длинные названия, много аргументов, везде префикс getNews. Было б прикольно сделать че-то типа */ $news = new News; $news->select()->byId(3)->get(); $news->select()->byCategory(5)->from(0)->length(10)->get(); $news->select()->from(20)->length(10)->orderBy('id')->orderType('desc')->get(); // но это тоже сомнительно. Как быть? Что посоветуете?
PHP: <?php //Одна новость $OneNew = new News($iId); //Несколько $News = new NewsCollection(); $News->SetPage($iFrom, $iCount); $News->FilterCategory($iCatId); $News->Desc('id'); //Ихмо мне удобнее через строчку писать, да у меня 22'', но все равно ИХМО лучше смотриться, чем длиннющая строка....
можно даже так, без дополнительной переменной PHP: <? $news = NewsCollection::create() ->setPage(30, 10) ->filterCategory(4) ->order('id', 'desc'); $tpl->l('news', $news); // assign array to template но каким образом я должен объяснить классу, что после order нужно делать запрос на выборку и возврат не экземпляра класса NewsCollection а именно массива? Тем более, что order можно оставить простой и тогда filterCategory должен возвращать массив. Имхо тут нужен еще метод get, который бы был завершающим и возвращал массив. (и возможно делал бы деструкт объекта)
Koc Тут всего навсего нужен Active Record. Тогда пока ты создаешь объект со всеми твоими вызовами у тебя внутри формируется только запрос. Потом при обращении к любому из свойств будь то просто или в foreach(это еще один намек на интерфейсы Countable и Iterator, которые я бы тоже реализовал), запрос будет вызываться и заполнять свойства. И вообще рекомендую сделать отдельную коллекцию для любых классов. Тобишь наследуешь от нее, задашь таблицы и свойства и все. И пофиг новости у тебя или пользователи или еще что...
kostyl у меня есть в одминке ManagerCommon и ListerCommon в них всякие методы getRows, parseRows. Покопаюсь по поводу итератора. Недавно в какой-то книженции читал о нем.
короче говоря как можно отследить обращение (а именно присвоение) к объекту? PHP: <?php class NewsCollection { private $param1 = 'e'; private $param2 = 'f'; function __construct() { } public function setParam1($param) { $this->param1 = $param; } public function setParam2($param) { $this->param2 = $param; } public function get() { return array('p1' => $this->param1, 'p2' => $this->param2); } } $n = new NewsCollection; $n->setParam1('a'); // установить параметр, но get не вызывать $c = $n->setParam2('b'); // установить параметр и вернуть метод get unset($n); $n = new NewsCollection; $c = $n->setParam1('a'); // установить параметр и вернуть метод get
PHP: <?php /** * Осуществляет доступ к свойству * @param string $sPropertyName имя свойства * @return mixed значение свойства */ public function __get($sPropertyName) { if (array_key_exists($sPropertyName, $this->_arProperties)) { if (!$this->_bIsLoaded) { $this->Reload(); } return $this->_DBResult->{$this->_arProperties[$sPropertyName]}; } else { throw new SObjectCollectionException(__METHOD__ . '=>Property ' . $sPropertyName . ' does not exsists'); } }
я слышал о магических методах, но опять-таки это - обращение к несуществующему свойству. PHP: <? $news = new NewsCollection; // ... установка параметров-условий $tpl->l('news', $news->list); // тут мы обращаемся к несуществующему полю list, вызывается метод __get, в нем выполняется запрос к БД, возврат результата в виде массива НО: мы все равно обращаемся к полю, а чем это лучше вызова еще одного метода?. да, можно сделать и так: PHP: <? $tpl->l('news', NewsCollection::create() ->setPage(30, 10) ->filterCategory(4) ->order('id', 'desc') ->list); // assign array to template но тогда уж логичнее писать так: PHP: <? $tpl->l('news', NewsCollection::create() ->setPage(30, 10) ->filterCategory(4) ->order('id', 'desc') ->get()); // assign array to template и не нужно использовать магические методы
Koc Ну как хочешь. Смотря как в шабонизаторе у тебя будет. Мой шабонизатор слабоват. Он нихеране умеет, поэтому я обычно передаю в шаблон уже другой массив. Обработанный и все такое, тоесть чистый html. Поэтому я этот массив формирую не в классе, а в коде пробегая по коллекции в цикле, где надо преобразовывая что надо. А потому валю массив в шабонизатор и пусть он сам разбирается...
Вот тут Ti пишет: это хорошо. Я смогу реализовать это посредством интерфейса IteratorAggregate. Но я не уверен, что мне нужно будет делать foreach. Как заставить выполняться запрос не только при использовании foreach но и по присвоению?
я использую phparser короче тема интересная, но пока сделаю с методом get() по которому будет происходить запрос. kostyl спасибо, что обратил мое внимание на Collection и предложил разделить на несколько классов (News для одной, NewsCollection для массива). Если у кого-то есть пожелания-предложения - велком.
Это дает возможность создавать произвольные свойства, а в API все должно быть четко задано. Для этого даже interfaces есть =)
Koc [vs] Я имел в виду сделать класс Collection. Потом сделать класс NewsCollection и унаследовать его от Collection. Collection оперирует свойствами. NewsCollection - декларирует лишь поля в базе данных, например в конструкторе, в помощью parent::AddField('Name', 'sname') тоесть метода предка. __get и __set описаны в предке. Я так имел в виду.
та не. Вся сложность в том, что fields, которые я буду получать - динамически задаются. К примеру можно написать get('id', 'title') // Это все в одной таблице, легко get('id', 'category_url') // тут мне нужно лезть в таблицу-связку для того, что б узнать к какой категории находятся новости (вложенный запрос) и еще в таблицу rewrites для получения nice_url для категории (join) То есть мне нужен или ORM или хотя б генератор запросов. а если до этого я еще поставил фильтр по категории? Жуть короче. Я в расстерянности.
Koc ну у меня уже все пашет, потому что у меня куча классов... Допустим по твоим проблемам у меня каждая коллекция содержит два объекта запроса. Тоесть у меня отдельный класс запроса, который динамически может напичкиваться всякой дрянью и в итоге выполняться. Ну поэтому все вместе работает почти ка ОРМ. Я считаю, что это должно инкапсулироваться в классе и ни в коем случае не маячить снаружи.
Если быть точным, тебе нужен Criteria. в принципе, можно что нить похожее написать, не таща к нему весь правильный ОРМ.
флоппик thanx, бум смотреть. а еще проблема, которую я не учел: новость находится в нескольких категориях. Указав в get: title, cat_titles мне нужно вернуть заголовок новости и массив названий категорий. Одним запросом никак? могу сделать запрос, который выдаст: id|заголовок|заголовок категории 1|Заголовок|раздел 1 1|Заголовок|раздел 3 3|Midway продали без торга|раздел N 5|Обновления Steam, TF2, Portal, Episode One и Two|раздел 1 5|Обновления Steam, TF2, Portal, Episode One и Two|раздел 3 но мне нужно как-то объеденить эти заголовки категорий в массив.
вы любите быдлокод? Да, капитан класс еще не дописан. Нужно подправить логику выдачи cat_ids, cat_titles, cat_urls и пока не обрабатывается ситуация когда нужны и категории и url's Это ужасно? Часть кода потом вынесу в абстрактный класс (в основном сеттеры).