У него понятнее и не нужно для каждого condition/operators создавать объект . Хотя если есть желание - выкладывай.
От прослойки БД требуется всего 3 вещи Уметь делать запросы. Уметь использовать биндинг (они же prepared statements). Иметь возможность наследоваться от него. Вот это PHP: <?php $result = Registry::get('Db') ->query() ->select('*') ->from('Posts as Post') ->join('Users as User', 'Post.UserID = User.ID') ->where('Post.TopicID = %d', $this->argv['TopicID']) ->compile()->run(); ?> Не имеет никаких преимуществ перед обычным PHP: <?php $query = "SELECT * FROM Posts as Post JOIN Users as User ON Post.UserID = User.ID WHERE Post.TopicID = ?"; $stmt = DB::prepare($query); // MySQLi::prepare($query); $stmt->bind('s', $this->argv['TopicID']); $stmt->exec(); ?> P.S. А сама идеология алиасов "Posts as Post" - меня убила. Зачем было именовать таблицы в множественном числе, чтобы потом приводить к единственному? Особая форма извращений?
SQL - это всё-таки полноценный язык. И делать над ним какую-то надстройку, какой-то билдер - это, извините меня, только самолюбие своё потешить. "Чистый" SQL гораздо лучше читаем, какие бы надстройки вы не сделали. ИМХО.
Нет. Смысла 0. Во-первых, убери копипаст в огромном количестве из кода. Во-вторых, у тебя есть два варианта - * моделей мало и они простые, но меняются часто, связей редко больше 1й. Соответственно выборки редко имеют больше 1го join и 3х условий в where - билдер тут, как зайцу стопсигнал. * моделей много, они сложные, но меняются редко, связей может быть и 3, и больше - билдер тут как швабра в истребителе (иметь можно, но бесполезно). Случаи, когда билдер бы помог это редкие исключения * моделей много, они сложные, и меняются часто. Я не видел такой задачи, где это происходит, но обычно это ошибка проектирования и там нужен скорее рефакторинг. Да! Есть такие задачи - это написание самой ORM Но если ты используешь ORM, то билдер тебе и даром не нужен. У тебя должен быть прозрачный маппинг PHP: <?php $model->filter('id', function ($val) {return $val >5}); echo $model; ?>
sorteros Это и ежу понятно, что чистый легче читаем, а билдер для того и служит чтобы собирать. Он ничё не должен, каждый делает как удобно, а то что там кто то умный написал - так это не постулаты...
А это ваши личные комплексы, что кто-то умный вам написал. Я вам говорю, исходя из личного опыта. В свое время за 8 месяцев с нуля написал порядка 6Мб говнокода. (при том что копипаста там было не 30% кода как у вас, а чуть более 6%) Билдер вне ОРМ не дает никаких удобств и преимуществ. Билдер в ОРМ - для вас не должен быть виден, иначе ОРМ для вас бесполезен. Удобно говнокодить лапшу копипастом, вроде такого - делайте. Возможно, когда-нибудь прозреете.
Билдер - часть внутренней архитектуры. Поэтому к обсуждаемому API форума отношения не имеет. Пользователю API не нужно думать о OMR с билдерами, ему нужен набор удобных методов для работы с форумом.
Simpliest я вот не пойму как рефакторить этот код. У нас есть новости, разделы, к которым прикреплена новость (одна в нескольких), есть nice_url для новости, nice_url для разделов. Одновременно все сразу это не нужно. Где-то нужен список заголовков и краткого содержания новостей из категории такой-то, где-то одна новость, отфильтрованная по id и категории со ссылками, в которые она входит. Как это правильно реализовать, что б без повторяющихся кусков кода в том числе?
Для начала определись что тебе нужно. nice_url? ЧПУ что ли? а каким боком он относится к новости? Один метод. Второй метод. Это все что нужно?
Касательно кода. У тебя сложости из-за того, что ты выполняешь запрос фактически во время его формирования. Сначала определись, что за запрос у тебя будет. Затем вызови в одном месте PHP: <?php $query = '' .... $result = $DB::query($query); .... return $result; ?>
ЧПУ. У каждой новости может быть своя ссылка. У каждой категории - тоже. Метод1, метод2... Я тоже так думал сделать. Но что если нужно будет фильтровать по категории, дате и пользователю? Да еще только те, которые не разу не редактировались. Будем писать метод 993: getNewsByUserNameMonthCategoryNotEditedOnce? Или напишем PHP: <? NewsCollection::instance() ->filterBy(array( 'user' => 'Alex', 'date' => '2009-12', 'categoryId' => 4, 'edited' => false )) ->get('date', 'title', 'nice_url', 'content_short'); Вот обсуждение [url=http://www.php.ru/forum/viewtopic.php?t=19636]http://www.php.ru/forum/viewtopic.php?t=19636[/url]
Дело в том, что 3,4,5 методов для наиболее типичных вариантов - это нормально. Но когда у тебя их (параметров фильтрации) становится больше - тебе придется рефакторить код. (Что самое интересное в этом случае ЧПУ станет не нужным и неэффективным) Это будет эффективнее попытки объять необъятное, поскольку у тебя уже будут готовые закономерности и требования к коду. Которые ты, на этапе проектирования, мог не видеть. Аналогия с профайлингом и оптимизацией - полная. Не имея конкретного решения оптимизировать нечего. В твоем случае решение может существенно упроститься, если ты будешь отдельно получать новости и отдельно категории. И только потом их объединять. Плюс прежний совет в силе - отделить формирование запроса от его выполнения.
сходу вижу что их будет куда больше. Если мы тем более про API говорим Возможно будет какое-то простое ЧПУ, на основе роутинга, без "супер"-уникальных ссылок. возможно ты и прав черт его знает. Я вообще хотел одним запросом получать и новости и категории в которых они а потом пыхом фильтровать. А формирование запроса и так частично отделено, сначала формируется и только в самом низу query. Но не перестает меня донимать мысль, что все было б просто круто с генератором: PHP: <? // ... if ($this->filter[categoryId]) $sql->leftJoin(self::TABLE, self::TABLE_NEWS2CAT, 'news_id=category_id') $sql->andWhere('category_id=?i', $this->filter[categoryId]) // ...
Я говорил про конкретный твой код. Да как-то некузяво оно отделено. И далеко не везде. с 99й по 277ю строки - сплошное спагетти-шаманство. Нет, я конечно понимаю как такой код получают (сам такое писал). Но это не нормально. Блин, да напиши проект с таким генератором. А лучше парочку. И все сам увидишь. Очинка выделки не стоит.
Как раааз реализую эту функциональность. В принципе, могу. Просто он еще сыроват да только для мускула драйвер есть Идёт из-за Зендовских стандартов именования и автолоада. плюс, чтобы названия классов разных подключенных библиотек случайно не скофликтовали. всмысле? ты про Джоины? ->get('User.*') ? о да. странно. смотрел код зенда — охуенный класс на 1000+ строк, фиг проссыш, что там написано. А с джоинами, сука, не работает. Такое впечатление, что создатели фреймворков не знают, что такое "Джоин". И? Оказалось безумно удобно. Допустим, у нас форум. Простой запрос типа: [sql]SELECT * FROM `prefix_topics` as `Topic` LEFT JOIN `prefix_posts` as `FirstPost` ON `FirstPost`.`ID` = `Topic`.`FirstPostID` LEFT JOIN `prefix_users` as `FirstUser` ON `FirstUser`.`ID` = `FirstPost`.`Author`.`ID` LEFT JOIN `prefix_posts` as `LastPost` ON `LastPost`.`ID` = `Topic`.`LastPostID` LEFT JOIN `prefix_users` as `LastUser` ON `LastUser`.`ID` = `LastPost`.`Author`.`ID`[/sql] PHP: <?php $query ->select('*') ->from('topics', 'Topic') // тут можно записать просто ->from('topics') и будет равно ->from('topics', 'topics') ->leftJoin('posts', 'FirstPost', 'FirstPost.ID = Topic.FirstPostID') ->leftJoin('users', 'FirstUser', 'FirstUser.ID = FirstPost.AuthorID') ->leftJoin('posts', 'LastPost' , ' LastPost.ID = Topic.LastPostID') ->leftJoin('users', 'LastUser' , ' LastUser.ID = LastPost.AuthorID') во-первых — префиксы расставляются автоматически. нету этих ужасных PHP: <?php $sql = "SELECT * FROM `" . $this->prefix . "topics`" во-вторых заметь — получилось не хуже, а, возможно. даже более понятно. чем native-sql в-третьих — у тебя есть этот запрос, который есть частью класса возвращающего коллекцию топиков. НО теперь представим, что мы захотели получить коллекцию топиков: 1. Несмотря на раздел и тип — список последних обновленных, для трекера 2. Для определенного раздела — упорядоченные сначала по типу, а потом - по дате 3. Список топиков, которые создал юзер з айди $id 4. Список всех топиков, имеющих тип "объявление" 5. Определённый изменяемый лимит для опостраничнивания 6. Количество найденных по топиков по одному из вышеназванных условий Ты что сделаешь? Будет на каждое из требований копипастить запрос, изменяя только часть? Или оставишь запрос в каком-то месте такого вида: PHP: <?php function getTopicsQuery($where, $order, $limit) { return "SELECT * ... $where $order $limit "; } тут тоже свои подводные камни. ты будешь писать запрос дважды, чтобы один раз поставить COUNT? а с квери билдером: Код (Text): 1. $q = $this->getTopics()->order('LastPost.ID')->page($page, 10); // подставится LIMIT зависимо от страницы 2. $q = $this->getTopics()->where('Topic.CatID = %d', $cat)->order('Topic.Type')->order('LastPost.ID') ... 6. $count = $q->getCount(); $result = $q->run(); Суть понятна, я думаю
я имел в виду, что у тебя указывается тип в where: ->where('id=%d', $_GET['id']) - это мне по нраву. В Kohana такого нет. а ничего кроме него и не требуется. Было б неплохо еще 2-3 примера: что задаем и что получим. И важна ли там очередность? Например я задал поля select, задал условия, но после взял и поменял поля (или добавил несколько). Префиксы у меня тоже автоматом расставляются: $db->fetchAll('SELECT id, title FROM ?t WHERE pid=?i', 'content', 3); mysqli_query('SELECT id, title FROM ad_content WHERE pid=3'); fetch_assoc ...
Блин точно как нибудь выложу, пофиг, что не заточенную версию. На данный момент такие фишки имеются: 1. Поддержка драйверов PDO и MYSQLi 2. Поддержка плейсхолдеров как на параметры, так и на данные. 3. Чистый функционал prepare-> execute 4. Почти полный объектный SQL билдер. 5. Поддержка синтаксиса MySQL PostgreSQL(пока только кавычки ) 6. Слабосвязанность функционал БД с SQLбилдером. 7. Не зависимость от порядка изменение частей запроса. 8. Поддержка функций, подзапросов, джоинов, алиасов и вроде схем... 9. Отдельный объект результатов Select Сейчас так не вспомню что еще. Скажите Simpliest, раз уж вы против, что лично вас не устраивает в таком наборе? (я просто спрашиваю, без претензий и т.п.)