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

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

>у фрейморка напрочь отсутствует документация
совсем, совсем не стыкуется с
>Сейчас onPHP — это достойная кандидатура на роль фундамента для веб-проекта любого масштаба.
сразу можно ставить жирный минус
В целом вполне согласен. Однако для тех, кто с ним знаком этого минуса не существует. Надеюсь в скором будущем минус обратиться в плюс.
Если хочешь развивать OpenSource проект — пиши документацию, поддерживай ее в актуальном состоянии, привлекай сторонних разработчиков.

Если что-то из этого не делается — проект будет топтаться на том же месте.
Документация нужна всегда, и к системе, с которой работаешь двадцать лет. Даже к той, которую сам написал. Невозможно держать все в голове.
Это конечно при условии, что эта система развивается и действительно делает что-то нетривиальное.
api — это тоже документация. :)
Я провтыкал или ссылки на фреймворк нет?
И хотелось бы увидеть бенчмарки с другими FW (если таковые имеются).
По ссылкам исправился.
По бенчмаркам — как будет время, сделаю, очень интересный момент.
Если будешь делать, то можно кинуть код для onPHP в рассылку, там помогут с оптимизацией. писькомерки такие писькомерки :-)
Не совсем понятно для чего создавать а затем «альтерить» таблички приходится вручную — у фрейворка есть скрипт — генератор проекта, перед созданием проекта прописываются все настройки конекта к БД,
поэтому вполне можно автоматом создавать таблички, как оно реализовано в той же Симфони
Да, я тоже об этом думал. Раз этого нет в стандартной поставке, есть возможность сделать патч и отправить его в рассылку =)
Мало того, он же еще и подсказывает какие запросы надо сделать 0_o
Видимо сделано чтобы человеки сперва все вручную перепроверили. А возможно просто нужно выбрать какую-то опцию
Нет там никакой такой опции. Можно только запустить генерацию без валидации БД.

По поводу того, что не обновляет базу автоматом — у меня есть некие предположения.
1) Никто не запускает генерацию меты на продакшене.
2) В MySQL вместо boolean используется тип tinyint. Так вот когда запускаешь генерацию меты, в которой объекты содержат булевые поля, скрипт предлагает накатить альтеры для смены типа с tinyint на bool. Это видимо недоработка в самом фреймворке, потому, что он явно развивается с прицелом на Postgres в ккачестве основной базы. MySQL там идет «что бы было». Получается, если бы база автоматически апдейтилась, то скрипт дергал бы её каждый раз по таким пустякам.

Хотя определенно есть смысл в том, что бы ввести новый флаг для генерации таблиц. Собсна это фопрос к Sherman-у )))
Почему же сразу к Денису. Уверен, что если Вы напишите патч к билдеру и он выдержит критику, то его добавят.
одно дело изменение в коде, которые покажет svn di, другое дело непрозрачные для программиста изменения в БД, которые непонятно сколько времени займут, что откатывать и т.п.
Как я понимаю, она достигается в основном за счет очень гибкого кэширования. Но есть и еще один фактор — модуль для php, который идет в комплекте. Часть классов, которые требуются постоянно, были оформлены в виде модуля, что несомненно ускорило их работу.

А классы, которые вынесены в модуль могут дублироваться в php-виде? Просто не на всех хостах, с которыми сталкиваешься при разработке есть возможность ставить редкие модули.
Конечно, все необходимые классы присутствуют в виде обычных php-классов, и использование модуля в общем-то не обязательно, если у проекта нет проблем с нагрузкой.
А что делать, если у меня на хостинге нет шела? Ну разные бывают тарифные планы, ведь так? Вот в чём прикол таких фреймворков???
Шел нужен только в процессе разработки, на хостинге нет смысла запускать генератор проекта.
хм. ну так у вас значит и запросы функционала небольшие :) зачем вам фреймворк вообще тогда? Вы много фреймворков без шелла установить сможете?
Возможно, что небольшие требования к функционалу… Но вот те же CI или Kohana + Doctrine установлю без шела. Где я могу прочитать, что данный фреймворк на голову быстрее, функциональнее, удобнее хотя бы приведённых выше?
Я вообще эту штуку не защищаю. Код без документации это дешевая поделка. Будь он трижды крут пользоваться им смысла нет.
>Будь он трижды крут пользоваться им смысла нет.
Голословно.
Я пользуюсь и вижу в этом смысл.

А вообще, Денис правильно сказал.
Высокий порог вхождения отчасти вызван отсутствием документации, вы так не думаете?
Да, этим в том числе.
Но это даже хорошо, ИМХО. Когда человек уже «вошел», то он знает фремворк уже хорошо, а не на уровне «почитал документацию, но не понимаю как оно внутри работает».

У onphp открыт код (и этот код прекрасен :), всегда можно посмотреть как оно внутри устроено и что делает. Документации на уровне api должно хватать для беглого поиска.
Фреймворк — это инструмент. Чем лучше владение инструментом, тем лучше получается продукт.

ps. кстати, последний год я вкладку с api-docs не закрываю в опере :)
Ага, не знал про CI :) Хотя кстати я наверное и ZF поставлю без шелла, подумалось сейчас. Короче, я был неправ :)
Я бы добавил в статью, что на этом фреймворке работает несколько крупных проектов:
rabota.ru
ucheba.ru
pravda.ru

P.S. Что он быстрый — это бабушка на двое сказала.
Так же timeout.ru
сомневаюсь что эта аналогия отражает действительность
Коля, ты не прав)
Не совсем, имелось ввиду аутичность:
неуверенность в себе, ранимость, предпочтение творческого уединения шуму внешней деятельности, склонность к мечтательности
Забыли упомянуть один из важных плюсов — прозрачное кеширование.

Это, наверное, один из немногих фремворках, где на ранних этапах разработки приложения (до появления действительно большой нагрузки) не надо задумываться о кеше вообще.

Т.е. вы знаете, что Author::dao()->getById(42); вернет вам объект из кеша если он есть, либо из базы и сама положит в кеш.
Для таких случаев есть кеш в sql базе, который кеширует все запросы. Делать ещё одну прослойку кеша, не обязательно.
при чем здесь кеш базы? Author::dao()->getById(42); вернет кешированную запись из того кеша который наcтроен, например memcache. Кеш в базе нам вообщем то не интересен, мы на него слабо влияем, да и не такой быстрый.
1) Это всё предварительная оптимизация, что достаточно бессмысленно.
2) Если есть уникальный ключ кешировать почти бесполезно, в силу пункта 3.
3) Кеш нужен только в разрезе всяких крупных десятиэтажных запросов (А особенно с подзапросами без точных условий) и тут не совсем понятно когда этот кеш должен скидыватся.
Если взять ваш пример, то допустим я вывожу 10 последних книг, в которых были коментарии.
TTL поменьше, и весь вопрос? Ну-ну.
4) Вообще не вижу особых технических проблем, по которым это нельзя сделать в любой ORM очень небольшими усилиями.
1) Если пишете личный блог то да, бессмысленно, а если работаете над крупным проектом, то будет нехорошо, если он после запуска ляжет.
2-3) Если кэш продержится (прежде чем устареет) хотя бы 5 минут, когда страничку посетит сотня, другая человек, то получается что есть резон кэшировать. К тому же, в реальной жизни редко возникает необходимость показывать стопроцентно актуальную информацию и лезть за ней в базу при каждом рефреше.
4) А вы попробуйте)
1) Потому что это уже не будет преждевременной оптимизацией. Я к тому, что нужно смотреть где и что в конкретном проекте кешируем. Всё кешировать фреймворком без ведома программиста — ничего хорошего…
2-3) Да это выход, но не панацея. Вот есть проект с большой нагрузкой. Пусть тот же каталог с авторами и их произведениями. Я хочу в кабинете автора выложить список его десяти последних произведений с последним комментарием в отзывах. Итого: текст + избыточность серилизации, да помноженное на количество авторов. То есть в данном случае будет просто так жраться оператива, потомучто даже если на главной у нас 200 человек в секунду, то где-то на авторе явно меньше.
Всё-таки таких штук на автокасте делать не стоит.
4) if( $var = $memcache_obj->get(md5( $result_sql_query ))) return $var;
Вы просто не до конца представляете себе как работает кеширование в onPHP. Там никто за вас ничего не делает. Начнем с того, что по дефолту все вообще работает без кэша. Далее, если есть потребность, вы можете выбрать одну из нескольких стратегий кэширования и выбрать куда кэшировать — файлы, мемкэш…

Кроме того, вы в состоянии не только определять стратегию кэширпования для конкретного DAO (класса объектов), но и для конкретного запроса.

Например:
$query = OSQL::select()->...;
Book::dao()->getByQuery($query, Cache::DO_NOT_CACHE); Собственно второй параметр может быть временем кеширования в секундах.

Чтобы не жралась оперативка, там где это действительно нужно, можно кешировать список id-шников например, а потом по id так же доставать объекты из кеша.
Спасибо!
То что вы говорите, в разрез расходится с «Author::dao()->getById(42); вернет кешированную запись из того кеша который настроен»…
Тут ключевое «из которого настроен», можно вообще не настраивать кеш :)
Ну я так и понял — настроил кеш, он везде где можно стал использоваться.
Как это было?

«Нас не устроили все фреймворки на php и поэтому мы написали свой. Он умеет то чего не умеют другие»

или

«Мы делали какой то проект и его архитектура нам так понравилась, что мы решили что это будет фреймворк»
Насколько мне известно (работал около полугода с разработчиками, активно использовал фреймворк, даже добавлен в контрибьютеры), идеалогия частично позаимствована у spring ffamework. Вообще, впечатления двоякие. С одной стороны, мощный, продуманный, учит правильно писать и проектировать. А с другой, фреймворк «для своих». Достаточно высокий порог вхождения. Поэтому сейчас сижу на symfony, но именно работа с onPHP направила мои стопы в эту сторону, за что бесконечно признателен.
Возможно, желающим разобраться поможет воскурение документации к spring-у.
Только не к современному, а версии эдак 2-2.5 :-)
Привет, Денис! =)
А можешь привести сравнение onPHP и Symfony? Было бы весьма любопытно.
Привет. Нет, потому что я не видел Symfony года 4 и не интересуюсь сейчас этим :-)
Невозможно в таком FW разрабатывать быстро.

Хотя-бы потому что вместо простого ясного SQL, предлагают ещё одну прослойку. Может даже на простом примере кажется и гибко, но…

Объясню на примере другого FW:

Files/Db/File/get.php — mysql класс
class Files_Db_File_get extends zzMysql{
  function onRun(){
    //prepare tags array
    $tags = preg_split('/\s*,\s*/', $this->tags);

    $this->tags = array_unique($tags);
    $this->countTags = count($this->tags);

    return parent::onRun();
  }
}

SQL файл Files/Db/File/get.zzMysql — mysql sql файл
SELECT
    fb.id
FROM `tag_file_rel` as tfr
JOIN `file_body` as fb ON fb.id = tfr.file_id
WHERE
    (tfr.`tag` in ~$tags~)
GROUP by tfr.`file_id`
HAVING count(tfr.`file_id`) = ~$countTags~
ORDER BY fb.`date`, fb.`id`

И пример использования:
    //get tags from input
    $search = array('tags' => 'php, onphp, framework, open source');

    //get data from SQL (ZZ is factory)
    $files = ZZ()->Files_Db_File_get($search)->toAssign('id');


* This source code was highlighted with Source Code Highlighter.

Если не ясно, объясню.
1) Берем массив $search (с 'tags') и передаем классу Files_Db_File_get, вызывая метод ->toAssign('id') — который возвращает результат запроса.
2) Переменная ->tags берется из массива. В процессе запроса, идет её преобразование из string в array.
3) Дальше происходит запрос в SQL, а переменные ~$tags~ и ~$countTags~ беруться прямиком из класса (само-собою в инкапсулированном виде).
3') ~$tags~ превращается из array в (…,…, ...), ~$countTags~ остается int.

При этом, таблицы tag_file_rel и file_body можно использовать как душе угодно (без связи 1 к многим fb.id = tfr.file_id).

Интерестно посмотреть подобный код на onPHP.
на примере постов с тегами будет что-то типа этого:
$postList =
  Criteria::create(Post::dao())->
  add(
    Expression::in('tagList.word', $tagList)
  )->
  getList();


* This source code was highlighted with Source Code Highlighter.

в $postList будет лежать массив объктов Post
Да, только сам запрос откуда формироваться будет? :)

Мне интерестно не как это использовать потом, а как разрабатывать.
Если не нужна оптимизация, то запроса вы даже не увидите, он соберется сам по схеме объекта, вы просто указали что получить, лезть на уровень raw sql вам абсолютно не нужно.
Я про схему такого объекта и спрашиваю.
Перечитайте статью, пожалуйста.
Там как раз пишут, что в onphp присутсвует кодогенерация.
Чтобы поиметь такой объект, достаточно написать несколько строк xml, а бизнес-, прото- и дао-классы сгенерируются сами.

Код, который вам привели достаточен для вывода списка постов. Ну еще шаблон нарисовать.
Я задаю простые вопросы.

1) Несколько строк xml — это сколько? Напишите, мне интерестно. Я понял основной концепт. Но интерестно применение на реальных задачах, а не в вакууме.

2) После написания xml, интерестно, на сколько будет понятно, что именно делает код?

Вы привели лишь пример, который состоит в моем случае из 2х строк, говоря, что внутри модели (которая автогенерится) может быть что угодно. В моем примере — модель тоже может быть чем угодно.
1. В статье, которую мы сейчас обсуждаем есть пример. Его можно посмотреть.
Для Вашего удобства я скопирую его в свой ответ (переписав под пост и теги):
        <class name="Post" type="final">
                <properties>
                        <identifier/>
                        <property name="title" type="String" size="50" required="true"/>
                        <property name="author" type="Author" relation="OneToOne" required="true" fetch="lazy"/>
                        <property name="tags" type="Tag" relation="OneToMany" required="true" fetch="lazy"/>
                </properties>
                <pattern name="StraightMapping"/>
        </class>


2. А это уже от Вас зависит :) Я не могу сказать, насколько Вам будет понятен код.
Ну зачем люди придумывают такой головняк?
Ведь все это быстро работает только на 10 запросах к коду в минуту(цифра с потолка), а когда 10 в секунду, а если 1000, все?

И начинаются появлятся какие то костыли, где употреблятся RAW SQL.
У нас около 2к запросов к бекендам в секунду. )
Критерия и сформирует Вам запрос, и соберет коллекцию объектов как результат. Никакого sql руками писать не надо.
Всегда можно посмотреть как будет выглядеть запрос вот таким образом:
echo
 Criteria::create(Post::dao())->
 add(
  Expression::in('tagList.word', $tagList)
 )->
 toDialectString(PostgresDialect::me())."\n";


* This source code was highlighted with Source Code Highlighter.
просто и ясно, это объекты
SQL код — это не просто, не ясно и к тому же не гибко, мое глубокое ИМХО
Часто за внешней простотой, ясностью и гибкостью объектов скрывается такие неудачные SQL запросы… То для отображения таблицы 10х10 вызывается сотня запросов, то для вывода одного числового столбца этой же таблицы вызывается десятиэтажный join, возвращающий три десятка полей. Не случайно во всех (наверное) ORM есть возможность напрямую указать SQL запрос, результаты которого ORM уже сама раскидает по объектам./свойствам.
В onPHP вам тоже никто не мешает сделать свой запрос и тоже построителем на объектах, а не куском SQL кода с переменными, который почти не поддается изменению. Да и к тому же, даже если запрос не оптимален, приложение не ляжет, т.к. данные в первую очередь возьмутся из кеша, а там они точно будут присутствовать, пока не ляжет кеш, или будут изменены сами данные, что повлечет их сброс из кеша.
Это-то понятно всё, сам обычно использую «высокоуровневый» ORM, а только перед деплоем перевожу запросы на «объектный SQL» типа $title = Query::create()->select('title')->from('table')->where('id=?', $id)->execute(); Почему не $title = Query::executeSQL('SELECT title FROM table WHERE id=?', $id); сам толком не знаю, результаты идентичны, а «парсится» запрос только в первый раз :), может потому что IDE автоподстановку делает :D
Я думаю что вы подсознательно понимаете, что при изменении требований легче изменить первый вариант, в который можно добавить и условную логику, а не снова хардкодить новую версию второго варианта.
Скорее потому что во всех примерах, мануалах и т. п. только такой стиль используется с объясненинями типа «не зависит от диалекта SQL» и т. д. и не хочется привязываться к, например, MySQL в надежде, что когда-нить сочтешь код достойным выкладывания в паблик и кто-нить захочет попробовать его, например, на PostgreSQL. Да и автоматически сгенерированные контроллеры, например, тоже содержат в таком стиле код, хочется однообразия в проекте. В общем скорее желание переносимости и унификации, чем легкость модификации, хотя она присутсвует, определённо, особенно при работе в IDE, знающей PHP, но не знающей SQK (по карйней мере внутри PHP).

P.S. А еще проверю завтра работанет ли у меня первый вариант с «виртуальными» полями, закодированными на PHP в классе модели (а-ля public function getCost() { return $this->getPrice()*$this->getCount(); } Если работает, то неоспоримое преимущество будет у «объектного SQL», поскольку закрывает от программиста контроллера детали реализации модели, хотя по хорошему все такие запросы надо в модель тащить и из контроллера вызывать getCostById(), но не всегда по хорошему получается
Я начинал писать туториал, но желающих помочь мне, к сожалению, не нашлось.
Так можно ваш туториал оформить в виде цикла статей на хабре. Я думаю эта идея найдет поддержку среди народных масс ;-)
Боюсь получить по шапке, но после «Видимо причина в том, что у фрейморка напрочь отсутствует документация» дальше читать не стал, на мой взгляд это самый существенный недостаток который просто перекрывает все вкусности данного продукта. Любой продукт OpenSource без документации это мертвый продукт
В новых версия появился OQL(Object query language). Это аналог hql их hibernate или JPA QL из jpa. Это dsl для извелечения объектов из хранилища.

Оно медленнее Criteria, поэтому для hl не подходит.

Также стоит упомянуть, что можно не пользоваться ORM, и работать в терминах чего-то типа RecordSet.

Пример:

dao->getCustomList();
criteria->getCustomList();

Вернет:

array(
array('id' => value, 'name' => value,… ,)
)

Не будет сборки объекта.

Есть возможность запустить вообще голый sql:

DBPool::getByDao($dao)->queryRaw(«sql here»);

Вернет голый db-specific курсор(или как там называется то что возвращает mysql_query, например). Но так делать не рекомендуется.

И последнее, насколько мне известно, в ряде компаний до сих пор активно используется используется onPHP и есть масса наработок, которые могли бы теоретически быть в репозитории(как минимум две версии olap, две версии Application и много-много misc utils), так как код там достаточно обобщенный, но этого почему-то не происходит. Я думаю, что по экономическим причинам(нужно дополнительные телодвижения, что заопенсорсить код).
Добавляю. Я тут чисто из любопытства решил его на PHP 5.3.x поднять. Так вообще никаких проблем, даже древняя версия onPHP типа 0.2.x работает на 5.3 без особых нареканий.
Это говорит еще о том что он спроектирован правильно.

Идеи в onPHP в основном взяты из Java, конкретно это Spring, Hibernate.

Тут дело не приходится иметь с лапша кодом, что не может не радовать.

Конечно чтобы разобраться в onPHP недостаточно базовых знаний, как минимум советуем ознакомится с книгой (Архитектура корпоративных программных приложений. Автор Фаулер М.)
Сколько строк/фактически файлов нужно для того, чтобы сделать ввод комментариев (не вывод списка комментариев, только ввод в базу), с валидацией емейла, или гостевой книги? А для регистрации (имя, логин, емейл без отправки проверки, два поля ввода пароля с проверкой на совпадение)?
Приведу пример для регистрации. Для ввода коментария просто будет немного другая форма.

У нас есть пользователь — User. Мета написана, классы сгенерированы.

Для начала мы добавим в прото-класс правила для валидации.

  1.     class ProtoUser extends AutoProtoUser 
  2.     {
  3.         public function makeForm($prefix = null)
  4.         {
  5.             $form = parent::makeForm($prefix);
  6.  
  7.             $form->get('mail')->
  8.                 setAllowedPattern(PrimitiveString::MAIL_PATTERN);
  9.  
  10.             // можно также добавить правила/ограничения на логин и т.д.
  11.  
  12.             return $form;
  13.         }
  14.     }

А теперь проверим данные пришедшие в post, добавив правила для идентичности паролей:
  1. $form =
  2.     User::proto()->makeForm()->
  3.     drop('id')->
  4.     add(
  5.         Primitive::string('passwordConfirm')->
  6.     )->
  7.     addRule(
  8.         'passwordConcistence',
  9.         Expression::eq(
  10.             FormField::create('password'),
  11.             FormField::create('passwordConfirm')
  12.         )
  13.     )->
  14.     import($_POST)->
  15.     checkRules();
  16.  
  17.     if ($form->getErrors()) {
  18.         // данные не корректны
  19.     }

PROFIT!
Также на форму навешиваются сообщения для вывода ошибки:

$form->addWrongLabel(
'passwordConcistence',
_('Пароли должны совпадать')
);

Выводим:

echo $form->getTextualErrorFor('passwordConcistence')

Также прошедшие валидацию значения сохраняются в форме, к ним можно получить доступ:

$form->getValue('login');

Также хочется отметить формы обладают примитивами типа «Бизнес объект» т.е.:

$form = Form::create();

$form->add(
Primitive::integerIdentifier('user_id')->of('User')
/*
* Id пользователя
* $form->getValue('user_id) вернет нам объект типа User
*/
)->add(
Primitive::identifierlist('user_ids')->of('User')
)->add(
Primitive::clazz('class_name')->of('SomeClass')
/*
* Ожидаем от формы название класса с учетом наследования и интерфейсов
*/
)->add(
Primitive::enumeration('type_id')->of('ExtendedEnumerationClass')
/*
* Ожидаем Id EnumerationClass-а
*/
)->add(

/*
* Прочие вкусности :-)
*/
);

$form->importMore(
$_POST
);


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

Form::create()->
add(
Primitive::string('pass')->
setImportFilter(Filter::textImport())->
setMin(6)->
isRequired()
)->
add(
Primitive::string('name')->
optional()
)->
add(
Primitive::string('description')->
setImportFilter(
Filter::chain()->
add(Filter::textImport())->
addFilter(Filter::stripTags())
)->
optional()
);
Нейминг вроде ничего, но многие конструктивные решения слегка устарели… На дворе spl_autoload, 5.3.2…

Не сильно тормозит этакая прикольная конструкция в global.inc.php set_include_path() с прописью всех путей поиска классов?

Думаю тормоза будут неслабые при переборе путей… Ибо по статистике профилировщиков (kachegrind) самые тормоза после БД, это «инклудинг» классов вместе с поиском и бизнес-логикой в циклах. Особенно касается include_once, require_once. В общем autoload хорошо справляется с этим. Если его нет, можно эмулировать через обработку ошибок… И максимум статики где это возможно используйте.

Попытка использовать типы-классы и базовые сущности выглядит интересной…
Нет, там нету тормозов. Там все кешируется при желании и кладтся в один файлик. В файлике асоциативный массив в котором ключик это имя класса, а значение — путь к файлу. Так что все работает довольно быстро.

Пробовал кстати запускать без кэширования путей и тогда да, сильно тупит. Примерно 0,3 сек на моем буке добавляется толькоза счет поиска и инклюда всех необходимых файлов.
Нужно использовать eAccelerator, xCache либо подобные продукты. Без них как-то туговато будет в любом смысле этого слова.
Самый быстрый вариант в onPHP, это autoload.classPathCache с хранением кэша классов в памяти.

В этом случае все классы(код) вообще объединяются в несколько файлов(в зависимости от путей).

Если разместить(указать путь в конфиге) эти файлы в /dev/shm проблема загрузки классов будет решена.
Насчет конфликта классов:

почти все знают ведь что делать :)
А точно «Аутичный»?

Может быть, всё таки, «Аутентичный»?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории