[vs] PHP: <?php $vasya = $mapper->findById(new User(), 9507); while(true){ $vasya->jump(); } угу, query же false вернет, если в уникальное поле попытаешься вставить совпадающий mail думаю что еше написать можно, libevent второй у меня явно не получится, хотя...
Mr.M.I.T. Не вижу в вашем сообщении аналогичного примера на ORM. Или это для него неподъемная задача?
Dagdamor книжный подход, в точности по книге фаулера, только на php, мне он меньше понравился как то, по сути для каждой модели свой маппер, просто возвращает их фабрика PHP: <?php $finder = new PersistenceFactory::getFinder('User'); $idobj = $factory->getIdentyObject()->field('name'); $collection = $finder->find($idobj); foreach($collection as $user){ echo $user->name; }
Dagdamor ну как сказать, это шаблоны корпоративных приложений, изначальная реализация на java и C# в общем смысл в том, что у меня маппер выполняет слишком много функций там кроме того, есть ленивая загрузка коллекций т.е. подргружаются допустим $user->friends каждый из которых в свою очередь тоже объект, но только по мере надобности, когда вызывается delete для юзера удаляется все что было внутри ну и из за большого количества ссылок в массиве на объекты, скрипт разрастается и захлебывается, там добавлен регистр объектов, который следит, что бы одинаковых объектов в системе не было, например user с одинаковым id, все это большая куча кода и ее тяжело поддерживать, поэтому там через фабрики сделан потом вся работа с моделями декорируется, вот в это например PHP: <?php UserService::delete($id); //удаляем все что с ним связанно
Dagdamor ах так, вот тебе =) буду переписывать твой говнокод на тру. PHP: <?php function makeFormYesNo($title, $description, $name, $value=1, $lang=true) { global $language; makeFormItem("header",$title,$description,$lang); $value=$value?1:0; $selected=array("","",$value=>" checked=\"checked\""); echo "<input class=\"radio\" type=\"radio\" name=\"$name\" value=\"1\"$selected[1]> $language[admin_yes] \r\n"; echo "<input class=\"radio\" type=\"radio\" name=\"$name\" value=\"0\"$selected[0]> $language[admin_no] "; makeFormItem("footer"); } PHP: <?php function makeFormYesNo($title, $description, $name,Laguage\Mutator $lang){ $form=new Form\Item(Form\Item::HEADER & Form\Item::FOOTER); $form->SetTitle($title) ->SetDesc($description) ->SetLaguageMutator($lang); $chbox1=new Form\Base\CheckBox(Form\Base\CheckBox::TYPE_RADIO,$name) ->SetValue(1) ->SetAttrs(Form\Base\CheckBox::ATTR_CHECKED); $chbox2=new Form\Base\CheckBox(Form\Base\CheckBox::TYPE_RADIO,$name)->SetValue(0); $form->AddItem($chbox1); $form->AddText(Laguage::AddMutator($lang)->Get("Admin_Yes")); $form->AddContext(Form\Base\HtmlEven::SPASE,Form\Base\HtmlEven::NEWLINE); $form->AddItem($chbox2); $form->AddText(Laguage::AddMutator($lang)->Get("Admin_No")); $form->AddContext(Form\Base\HtmlEven::SPASE); return $form->Html(); } короче, на реализацию уйдет ещё пол года. пойду возьму зенд, ибо зачем изобретать свой велосипед?
а у меня как то так было PHP: <?php Forms::form(); Forms::input(array('name'=>'login')); Forms::input(array('name'=>'password','type'=>'password')); Forms::view(); а потом решил, что это нафиг никому не надо
Mr.M.I.T. )))))))))))))))))))))))))))))))))))) А чо, в Зенд полноценные формы добавили? Вроде ж не было их в палате царской.
Неее! Возьми Yii + Zend. Zend сам по себе это лего, только очень продвинутое. Его что бы юзать, надо рочень хорошо разбираться в паттернах и.т.д., уметь чётко проектировать. В общем слишком долго вливаться, лучше его как библиотеку.
Падабу, ты правильно заметил, Фаулер писал с использованием java и c#, а ты пишешь НА php, поэтом код выглядит не в тему в какой-то степени
Костян ну вот такой вариант еше есть, тоже по мапперу на модель http://phpdatamapper.com/documentation/usage/finders/
А какой смысл в генерации класса модели? Почему нельзя наследовать весь общий функционал от абстрактного класса? Объявить члены-класса-таблицы ручками не сложнее, чем каждый раз делать перегенерацию после изменения структуры таблицы.
Духовность угу, я все вынес, когда пользоваться начал, просто топ забыл обновить, там не только это менял, как допереставлю систему - обновлю
Угу. Я в своей реализации подобного пошел чуть дальше: 1. Через __call вызываю виртуальные методы моделей: PHP: $user = new User(); $user->setLogin('Test'); $user->setPassword('qwerty'); $mapper->add($user); зачем так было делать? Для унифицирования интерфейса, ведь не исключена ситуация, что нам потребуется ЯВНО реализовать методы моделей, например реализовать setPassword в виду какой-то логики: PHP: fublic function setPassword($pass) { if ($pass) $this->row['pass'] = md5($pass); // и т.п. } т.е. я могу обращаться и присваивать свойства модели через $obj->prop_name, но в большинстве случаев работают виртуальные геттеры/сетеры. 2. Все атрибуты модели имеют "карту" - это настройки вида: PHP: /** * Карта атрибутов модели. * Перечисляются в дочерних классах в виде массивов следующего содержания: * * 'first_name' => array('db_element' => true, * 'db_field_name' => 'user_first_name', * 'default_value' => null, * 'validators' => array( * 'Common/Decimal' => array('unsigned' => false), ...) * ) * * Допустимые свойства и их возможные значения: * * type Тип данных свойства. Тип указывается только для сложных, не скалярных типов, * например, для таких, как объект Module_Common_Type_Datetime, * Module_Common_Type_Email и т.д. Если тип не указан, значит, это скаляр. * db_element [true|false] должно ли это свойство записываться в БД. * В большинстве случаев это свойство устанавливается в true. Исключения составляют * какие-то "вспомогательные" свойства объекта, которые допустимо иметь в качестве * членов класса, но записывать в БД не нужно. * Например, свойство ID Primary Key для каждой таблицы имеет значение false по * причине того, что никогда не пишется в таблицу, а является лишь указателем * на запись, т.е. фактически является "вспомогательным" в данной терминологии. * db_field_name Имя поля таблицы данных, ассоциируемое с данным свойством класса. * default_value Значение свойства по умолчанию, при инстанцировании объекта. * Данный параметр никак не связан со значением DEFAULT SQL-описания таблицы данных. * validators Массив валидаторов, которые должны быть применены к свойству при * присвоении ему значения. * * @var array */ ну и модели выглядят так: PHP: <?php class Module_User_Model_User extends Base_Model { protected static $db_field_prefix = 'user'; protected static $model_attributes = array ( 'id' => array('db_element'=>FALSE, 'default_value' => 0, 'validators' => array( 'Common/Decimal' => array('unsigned' => false), ) ), 'active' => array('db_element'=>TRUE, 'db_field_name' => 'user_active', 'default_value' => 1, 'validators' => array( 'Common/EmptyNull' => array(), 'Common/Decimal' => array('unsigned' => true), 'Common/IntRange' => array('min' => 0, 'max' => 1), ) ), 'group' => array('db_element'=>TRUE, 'db_field_name' => 'user_group', 'default_value'=> 2, // 2 - ID группы Пользователи 'validators' => array( 'Common/Empty' => array(), 'Common/Decimal' => array('unsigned' => true), ) ), 'login' => array('db_element'=>TRUE, 'db_field_name' => 'user_login', 'validators' => array( 'Common/EmptyNull' => array(), 'Common/StringLength' => array( 'start' => 0, 'stop' => Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH), 'Common/CharPassword' => array(), ) ), 'mail' => array('type' => 'Module_Common_Type_Email', 'db_element' => TRUE, 'default_value' => null, 'db_field_name' => 'user_mail', 'validators' => array( 'Common/StringLength' => array( 'start' => 0, 'stop' => Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH), 'Common/Email' => array(), ) ), 'password' => array('db_element'=>TRUE, 'db_field_name' => 'user_password', 'validators' => array( 'Common/CharPassword' => array(), ) ), 'regdate' => array('type' => 'Module_Common_Type_Datetime', 'db_element'=>TRUE, 'db_field_name' => 'user_regdate', 'default_value' => 'now', 'validators' => array( ) ), 'visitdate' => array('type' => 'Module_Common_Type_Datetime', 'db_element'=>TRUE, 'db_field_name' => 'user_visitdate', 'default_value'=>null, 'validators' => array( ) ), 'ip' => array('db_element'=>TRUE, 'db_field_name' => 'user_ip', 'default_value'=>null, 'validators' => array( //'Common/FixedStringLength' => array(15), ) ), 'first_name' => array('db_element'=>TRUE, 'db_field_name' => 'user_first_name', 'default_value'=>null, 'validators' => array( 'Common/StringLength' => array('start' => 0, 'stop' => 30), ) ), 'last_name' => array('db_element'=>TRUE, 'db_field_name' => 'user_last_name', 'default_value'=>null, 'validators' => array( 'Common/StringLength' => array('start' => 0, 'stop' => 30), ) ), 'age' => array('type' => 'Module_Common_Type_Datetime', 'db_element'=>TRUE, 'db_field_name' => 'user_age', 'default_value'=>null, 'validators' => array( ) ), 'sex' => array('db_element'=>TRUE, 'db_field_name' => 'user_sex', 'default_value'=>null, 'validators' => array( 'Common/StringLength' => array('start' => 1, 'stop' => 1), 'Common/VarEnum' => array('enum' => array('M', 'F')), ) ), 'city' => array('db_element'=>TRUE, 'db_field_name' => 'user_city', 'default_value' => 0, 'validators' => array( 'Common/Decimal' => array('unsigned' => true), ) ), 'region' => array('db_element'=>TRUE, 'db_field_name' => 'user_region', 'default_value' => 0, 'validators' => array( 'Common/Decimal' => array('unsigned' => true), ) ), 'country' => array('db_element'=>TRUE, 'db_field_name' => 'user_country', 'default_value' => 0, 'validators' => array( 'Common/Decimal' => array('unsigned' => true), ) ), 'phone' => array('db_element'=>TRUE, 'db_field_name' => 'user_phone', 'default_value'=>null, 'validators' => array( 'Common/StringLength' => array( 'start'=> 0, 'stop' => Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH), ) ), 'icq' => array('db_element'=>TRUE, 'db_field_name' => 'user_icq', 'default_value'=>null, 'validators' => array( 'Common/Decimal' => array('unsigned' => true), 'Common/IntRange' => array( 'min' => 10000, 'max' => Module_Common_Validator_IntRange::PHP_MAX_INT_32) ) ), 'url' => array('db_element'=>TRUE, 'db_field_name' => 'user_url', 'default_value' => null, 'validators' => array( 'Common/StringLength' => array( 'start' => 0, 'stop' => Module_Common_Validator_StringLength::VARCHAR_MAX_LENGTH), 'Common/Url' => array() ) ), ); /** * TRUE, если пользователь принадлежит к группе "пользователи" * * @var boolean */ protected $is_user; /** * TRUE, если пользователь принадлежит к группе "администраторы" * * @var boolean */ protected $is_administrator; public function isGuest() { // У гостей ID модели User всегда меньше 0 (-1) // поэтому лезть в базу не обязательно return $this->getId() < 0; } public function isUser() { if ($this->is_user === null) { $Module_Group_Mapper_Group = new Module_Group_Mapper_Group(); $group = $Module_Group_Mapper_Group->findGroupByAlias('user'); $this->is_user = $this->getGroup() == $group->getId(); } return $this->is_user; } public function isAdministrator() { if ($this->is_administrator === null) { $Module_Group_Mapper_Group = new Module_Group_Mapper_Group(); $group = $Module_Group_Mapper_Group->findGroupByAlias('administrator'); $this->is_administrator = $this->getGroup() == $group->getId(); } return $this->is_administrator; } public function getFullName() { return $this->first_name. ($this->last_name ? ' '.$this->last_name : ''); } public function getFullNameOrLogin() { return $this->getFullName() ? $this->getFullName() : $this->getLogin(); } public function getAgeDay() { if ($this->age && $this->age instanceof Module_Common_Type_Datetime) { return $this->age->format('j'); } return null; } public function getAgeMonth() { if ($this->age && $this->age instanceof Module_Common_Type_Datetime) { return $this->age->format('n'); } return null; } public function getAgeYear() { if ($this->age && $this->age instanceof Module_Common_Type_Datetime) { return $this->age->format('Y'); } return null; } /** * @see parent::getId() */ public function setId($id) { if (!empty($this->data['id']) && $this->data['id'] != -1 && $this->data['id'] != $id) { throw new LogicException('Нельзя переопределить значение ID объекта модели '. get_class($this)); } $this->id = $id; return true; } protected function _setUrl($url) { return $url === 'http://' ? null : $url; } protected function _setPassword($password) { if ($password === null || $password === '') { return null; } return md5($password); } } ?>
Духовность интересная идея, а что в самом маппере? как вызываются и возвращают ошибки валидаторы? проблема памяти не вставала? я думал сделать регистр моделей, что бы по 10 раз один и тот же объект не создавать над Lazy Load коллекций не думал?пока не нашел где мне это надо, но если удаляем допустим юзера я бы не отказался если б за ним удалялось все остальное
концептуальных отличий от твоего меппера нет. принцип тот же. остальное - тонкости архитектуры, которые смысла описывать нет. при присвоении свойства объекту модели происходит валидация. Валидация в модели носит лишь уведомительный характер. Принимать решение, что делать с моделью с ошибками должен слой, оперирующий с этой моделью (контроллер/меппер): PHP: $user = new User(); $user->setLogin(''); // возникла ошибка, но свойство присвоилось if (!$user->getErrors()) { $mapper->add($user); } else { echo 'Ошибка!'; } В общем, это тонкости все, которые накладываются на уже существующую архитектуру и существующие по историческим причинам. Я считаю своим достижением в данном решении то, что я сделал не просто сухой меппинг табличных данных, а реализовал ситуацию, когда каждое свойство класса может быть либо скаляром (что нужно в 90% случаев), либо объектом какого-то ТИПА - объектом Datetime, Email и т.д: PHP: $user = Mapper::find(1); $user->getVisitdate() // возвращает объект Module_Common_Type_Datetime который extends Datetime ->getDateAsStrinп(); // Сегодня, 12:23 $user->getMail()->getDomain(); // mail.ru
PHP: <?php $user = Mapper::find(1); $user->getVisitdate() // возвращает объект Module_Common_Type_Datetime который extends Datetime ->getDateAsStrinп(); // Сегодня, 12:23 $user->getMail()->getDomain(); // mail.ru а вот про это я и спрашивал реализацию Мэтта Зандстра видел? есть на что посмотреть
ты про книгу? мне книга очень не понравилась - не читабельная она какая-то, воды очень много. Фаулер хоть и сложнее пишет, но доходит больше
Духовность с Фаулером не сравнить конечно, но по php я лучше не встречал по крайней мере, странно, может издание не то? Там совсем другая реализация, которая скорее ближе к такому варианту: http://phpdatamapper.com/ но там тоже свои плюсы