Я не хочу, чтобы кто-то говорил: «Вы не должны изобретать велосипед, использовать ORM с открытым исходным кодом» ; У меня есть неотложное требование и я не могу переключиться.
Я занимаюсь небольшим ORM, который поддерживает кеширование. Даже не поддерживая кеширование, мне нужна эта функция в любом случае, чтобы знать, когда писать объект на хранение или нет. Шаблон – DataMapper.
Вот мой подход:
У меня есть абстрактный класс под названием AbstractModel
который наследует все модели. Он имеет открытый метод isDirty()
с частным (может быть защищен, если необходимо) атрибутом is_dirty. Он должен возвращать true или false в зависимости от изменения данных объекта или нет, поскольку он был загружен.
Проблема заключается в следующем: существует ли способ повысить внутренний флаг "is_dirty"
без кодирования в каждом $this->is_dirty = true
? Я имею в виду: я хочу, чтобы сеттеры были $this->attr = $value
большую часть времени, за исключением необходимости изменения кода для бизнес-логики.
Другим ограничением является то, что я не могу полагаться на __set
потому что в конкретном классе модели атрибуты уже существуют как частные, поэтому __set
никогда не __set
.
Есть идеи? Приводятся примеры кода из других ORM.
Одна из моих идей заключалась в том, чтобы изменить шаблон сеттеров NetBeans, но я думаю, что должен быть способ сделать это, не полагаясь на среду IDE.
Еще одна моя мысль заключалась в создании сеттеров, а затем изменении имени частного атрибута с подчеркиванием или чем-то еще. Таким образом, сеттер будет звонить в __set
и иметь некоторый код для работы с флагом "is_dirty"
, но это немного нарушает концепцию POPO, и это уродливо.
Attantion!
Мое мнение по этому вопросу несколько изменилось в прошлом месяце. Хотя ответ, который по-прежнему действителен, при работе с крупными объектными графами, я бы рекомендовал вместо этого использовать шаблон Unit-of-Work. Вы можете найти краткое объяснение этого в этом ansewer
Я немного смущен, как то, что вы называете-Model связано с ORM. Это смущает. Тем более, что в MVC модель представляет собой слой (по крайней мере, вот как я его понимаю , а ваши «Модели» мне больше похожи на объекты домена ).
Я буду считать, что у вас есть код, который выглядит так:
$model = new SomeModel; $mapper = $ormFactory->build('something'); $model->setId( 1337 ); $mapper->pull( $model ); $model->setPayload('cogito ergo sum'); $mapper->push( $model );
И, я буду предполагать, что у того , что вы вызывают-модель, есть два метода: конструктор, который будет использоваться агентами данных: getParameters()
и setParameters()
. И что вы вызываете isDirty()
прежде чем mapper isDirty()
вы» – «Модель » и вызовет cleanState()
– когда данные cleanState()
данные в « что вы вызывать» .
Кстати, если у вас есть лучшее предложение для получения значений от-и-к карте данных вместо
setParameters()
иgetParameters()
, пожалуйста, поделитесь, потому что я изо всех сил пытался придумать что-то лучше. Это кажется мне утечкой инкапсуляции.
Это приведет к тому, что методы сопоставления данных будут выглядеть так:
public function pull( Parametrized $object ) { if ( !$object->isDirty() ) { // there were NO conditions set on clean object // or the values have not changed since last pull return false; // or maybe throw exception } $data = // do stuff which read information from storage $object->setParameters( $data ); $object->cleanState(); return $true; // or leave out ,if alternative as exception } public static function push( Parametrized $object ) { if ( !$object->isDirty() ) { // there is nothing to save, go away return false; // or maybe throw exception } $data = $object->getParameters(); // save values in storage $object->cleanState(); return $true; // or leave out ,if alternative as exception }
В фрагменте кода
Parametrized
– это имя интерфейса, объект которого должен быть реализован. В этом случае методыgetParameters()
иsetParameters()
. И у этого есть такое странное имя, потому что в ООПimplements
слово означает has-ability-of , в то время как средствоextends
означает -a .
До этой части у вас должно быть уже все похожее …
Теперь вот что должны делать методы isDirty()
и cleanState()
:
public function cleanState() { $this->is_dirty = false; $temp = get_object_vars($this); unset( $temp['variableChecksum'] ); // checksum should not be part of itself $this->variableChecksum = md5( serialize( $temp ) ); } public function isDirty() { if ( $this->is_dirty === true ) { return true; } $previous = $this->variableChecksum; $temp = get_object_vars($this); unset( $temp['variableChecksum'] ); // checksum should not be part of itself $this->variableChecksum = md5( serialize( $temp ) ); return $previous !== $this->variableChecksum; }
Например, я бы сделал прокси-сервер:
class BaseModel { protected function _set($attr, $value) { $current = $this->_get($attr); if($value !== $current) { $this->is_dirty = true; } $this->$attr = $value; } }
Затем каждый дочерний класс будет реализовывать свой сеттер, вызывая _set()
и никогда не устанавливая свойство напрямую. Кроме того, вы всегда можете вводить более классный код в каждый _set
и просто вызывать parent::set($attr, $processedValue)
_set
parent::set($attr, $processedValue)
при необходимости. Затем, если вы хотите использовать магические методы, вы создаете прокси-сервер для метода свойств, который _set
на _set
. Я полагаю, что это не очень POPO.
хотя этот пост старый, но как об использовании событий для уведомления слушателей, когда isDirty () происходит? Я бы подошел к решению с событиями.