ORM для встроенных модулей

Пока еще модули Topic, Comment, User… не являются наследниками ORM классов, а зачастую хочется использовать преимущества ORM в плагинах, дополняющих данные модули. Скажем релейшены.

Конечно, можно отредактировать класс модуля жестко:
заменить
extends Module

на
extends ModuleORM

Только придется прописывать еще в методе Init():
parent::Init();

+ сделать тоже самое для сущностей.
Согласитесь, каждый раз при развертывании проекта выполнять эти манипуляции совсем неинтересно. Да и в итоге можно забыть, где и что менять. При чем, при обновлении модуля придется все вставлять заново.

Поэтому возникла идея, чтобы сделать это в плагине.
Итак. К примеру, нам нужно сделать, чтобы в плагине можно было пользоваться ORM для Topic.
Для этого создаем два модуля с сущностями:

1) Модуль плагина переопределения классов Topic

<?php
/**
 * Модуль топиков
 *
 */
class PluginOrm_ModuleTopic extends PluginOrm_Inherit_ModuleTopic {		
	
	public function __call($sMethod,$aParams) {
		try {
			return parent::__call($sMethod,$aParams);
		} catch (Exception $e) {						
			if (preg_match("/{$sMethod}/",$e->getMessage())) {			
				$sEntityShortName = preg_replace('/(.+_)*Module([^_]+)(_.+)*/','$2',__CLASS__);				
				$sMethod = str_replace($sEntityShortName,$sEntityShortName.'wrapper',$sMethod);
				return call_user_func_array(array($this,"PluginOrm_Topicwrapper_$sMethod"), $aParams);
			}
		}
		return;
	} 
	
}
?>

2) Сущность переопределения для сущности Topic

<?php
class PluginOrm_ModuleTopic_EntityTopic extends PluginOrm_Inherit_ModuleTopic_EntityTopic {    	
    
	protected $oEntityORM = null;

	public function getORM() {
		if (!$this->oEntityORM) {					
			$this->oEntityORM = LS::GetEntity('PluginOrm_Topicwrapper_Topicwrapper');			
			$aData = array_intersect_key(
				$this->_aData, 
				array_flip($this->oEntityORM->_getFields())
			);			
			$this->oEntityORM->_setData($aData);							
		}		
		return $this->oEntityORM;
	}	
}
?>

3) Модуль обертки для ORM

<?php
/**
 * Модуль топиков для совместимости ORM
 *
 */
class PluginOrm_ModuleTopicwrapper extends ModuleORM {	
}
?>

4) Сущность обертки для ORM
<?php
class PluginOrm_ModuleTopicwrapper_EntityTopicwrapper extends EntityORM {  
	
	protected $aRelations = array (		
		'property_values' => array (
			self::RELATION_TYPE_MANY_TO_MANY,
			'PluginOrm_ModuleProperty_EntityPropertyValue',
			'property_value_id',
			'db.table.property_value_topic',
			'topic_id'
		),			
	);
}
?>

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

Config::Set('db.table.topicwrapper', '___db.table.prefix___topic');


Как всё работает.
Если будет запрошен какой-то незнакомый метод модуля Topic (например, Topic_GetTopicItemsbyTitleLike()), то магический метод __call перехватит его и попытается вызвать данный метод, но уже ORM модуля обертки.

Теперь в других ORM модулях вашего плагина можно смело указывать отношение с ModuleTopic_EntityTopic
Сама ORM сущность может быть вызвана так.


$oTopicORM=$oTopic->getORM();


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

7 комментариев

avatar
магия
  • ort
  • 0
avatar
Ort, скажи, когда появится возможность модули плагинов называть «cool_name_plug», а класс CoolNamePlug.
Сейчас доступны только односложные названия
avatar
уже можно
avatar
Чего-то не фурычит
Пробывал
LS::Ent('PluginTest_ModuleTopicWrapper_EntityTopicWrapper');

выбивало:
<b>Fatal error</b>:  Class 'ModuleTopicWrapper_EntityTopicWrapper' not found in <b>...\engine\classes\Engine.class.php</b> on line <b>709</b><br />


В самом Engine везде strtolower() используются вместо func_underscore() для классов
Версия 5.1
Для самих названий плагина работает, а для названий модулей нет:
// Модуль плагина
				$sPath .= 'plugins/'.func_underscore($aInfo[self::CI_PLUGIN])
					.'/classes/modules/'.strtolower($aInfo[self::CI_MODULE])
					.'/'.$aInfo[self::CI_MODULE].'.class.php';
avatar
точно, перепутал с названием плагинов
avatar
Что-то не хочется в детали вникать, поэтому просто спрошу: а если, имея этот установленный плагин, я захочу работать с модулями и сущностями по старой методе — проблем не возникнет?
avatar
Это еще не плагин, а идея, которую я обкатываю у себя. Пока всё работает. Смысл ведь в том, что ORM не перекрывает старые методы, а запускается, когда не находит оных.
Есть, конечно, вопросы. Например, ActiveRecord пока неполноценен и работает через

$oTopic->getORM()->update();

При сохранении или удалении в ORM происходит проверка на связи.
Поэтому после встроенного метода сохранения необходимо еще вызывать ORM-ский.
Собственно, всё это делалось для того, чтобы можно было строить отношения с ORM сторонних модулей к модулям без ORM.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.