PHP 5 Преобразование в свой тип обекта
/ | \
User Agent Company
Теперь стоит задача обединить их в одну сущность. Сделал GlobalUser со всеми необходимыми полями. В User, Agent, Company перегрузил методы get_название_поля() так чтоб данные доставались из нужних полей GlobalUser. Ето сделано для того чтоб не переписывать кучу кода (ну типа для совместимоси с уже сделаным). Но есть проблема. Я получаю с БД сущность типа GlobalUser. Данные в ней то есть, а вот методов get_название_поля() которые перегружают доступ к полям к примеру Юзера там нет, потому что они описаны в User
Как мне привести GlobalUser к User ???
ЗЫ. Я могу написать Конструктор для User которому буду передавать GlobalUser и он с него скопируется, но ето не очень подходит :(. Хочется чтоб ето был один обект в памяти. Я понимаю что то что я делаю полный изврат, но в User Agent Company нет новых полей, только методы, которые производят дорступ к полям. Так что нарушения целосности данных не произойдет.
$GlobalUser = new GlobalUser();
$User->globalUser = & $GlobalUser;
PS Обычно во всех (под всеми я наивно понимаю Java, т.к. только пых и немного Java я и знаю :)) преоброзование приводится выше по ирархии, т.е. от User к GlobalUser.
Раньше под юзерами, агентами и компаниями выступали конкретные пользователи и у каждого из них были свои потребности и права по использованию сайта. Теперь начальству надо чтоб у каждого пользователя была полная функциональность, которая предоставляется етими тремя сущностями. Тоесть залогинился и виступаеш и как юзер и как агент и как компания. Плодить записи в трех таблицах и связывать их - полный изврат в котором точно ногу вывернеш.
$GlobalUser = new GlobalUser();
$User->globalUser = & $GlobalUser;
Думал о таком но ету идею отбросил потому что в юзере, агенте, компании придется очень много перегружать и перенаправлять на его поле глобал юзер.
Хотя если подумать, то пожалуй может и стоит попыхтеть над модернизацией трех сущностей и етим все и обойдется. Я подумаю над етим.
[quote=shine]Если я правильно понял и теперь нужно все данные хранить в одной таблице, то добавляйте в нее дополнительное поле где будете хранить имя класса и при создании объектов, сразу после выборки, создавайте не абстрактный Globaluser а конкретный класс имя которого вы можете прочитать в новом поле. То есть GlobalUser создавать можно, но только если в поле записи храниться название этого класса.[/quote]
Совсем неприемлимо, потому что одна запись может выступать и как юзер и как агент и как компания в зависимости от контекста использования. Кроме того придется теперь использовать сам GlobalUser с полной функциональностю. Сами классы Юзер, Агент, Компания оставлены только для совместимости с предыдущим уже не маленьким кодом. (Правда етой совместимоти пока добиться не удается :) )
[quote=shaelf]GlobalUser В данном контексте должен использоваться как абстрактный и доступа к нему напрямую не должно быть (если он просто описывает общую сущность полей)[/quote]
Как уже сказал выше - неподходит, потому что и сам ГлабалЮзер будет использоваться теперь с полной функциональностю.
[quote=shaelf]нужно просто перенастроить 3 дочерних на родительскую таблицу[/quote]
Ето уже сделано. Кроме того сам ГлобалЮзер тоже настроен на ету таблицу.
[quote=shaelf]Приводить от GlobalUser к User возможным не представляется (извратится можно, но с любыми комментами ты через полгода сам будешь смотреть и не понимать что ты написал).[/quote]
Вот и не понимаю как извратиться. Создать екземпляр юзера и копийнуть туда поля глобалюзера не совсем подходит.
[quote=shaelf]преоброзование приводится выше по ирархии, т.е. от User к GlobalUser[/quote]. В сишке кажись получится. Но не уверен. Да ето изврат но может всеже стоит както провернуть.
Короче что я сейчас вижу. Либо непонятно как извращаться для приведения типа. ( shaelf подскажи как ;) ) либо делать то что предложил Mr.Hacker
Тут же и прошу совета что лутше.
1. Если роли (я воспринимаю юзера, компанию и агента именно как роли) больше не нужны, но не хочется терять их (классы), то создавай ещё один (общий) и его юзай. Если у тебя всё же будет какое разделение (по ролям), то мне кажется проще сделать именно роли и по этим ролям подгружать данные классы.
PS ИМХО вообще, лучше объеденить в один класс...
ЗЫ. Ето дело немного отложили так ка появилась более приоритетная задача, но как сделаю - напишу получилось или нет и сколько было проблем :)
Короче сокращенная история.
Я уже розказывал на форуме когдато что сделал себе на РНР5 псевдопроперти. Реализовал ето в родительском почти для всего классе
function __set($Name, $Value)
{
if (method_exists($this, 'set_'.$Name)) {
return call_user_func(array(&$this, 'set_'.$Name), $Value);
}
else {
return parent::__set($Name, $Value);
}
}
function __get($Name)
{
if (method_exists($this, 'get_'.$Name)) {
return call_user_func(array(&$this, 'get_'.$Name));
}
else {
return parent::__get($Name);
}
}
}
Дальше надо было сделать сайт на 3 языках Ну с шаблонами проблем нет. Смарти поддержывает такое. А как быть с сущностями в БД.
Написал еще класс MLEntity extends Entity. Код не привожу потомучто большой и непонятный.
Суть в БД столбцы "поле__язык". Там тоже все через __гет __сет. А используем поле как обичное. Тоесть $instance->field. А уж тогда MLEntity смотрит что field многоязычний и решает на каком языке его возращать и устанавливать.
Дальше поверх него стоит еще класс который умеет роботать со своими числовыми полями как с текстовыми строчками определенными в таблице-словаре в БД.
Ето все особо к сути не относится. Просто чтоб видно было что ето все уже достаточно запутано, зато очень удобно и функционально
Тоесть так
Entity
|
MLEntity
|
DictEntity
|
GlobalUser
На каждом уровне наследывания кроме GlobalUser перегружаются __get/__set
Теперь надо синхронизировать поля в User с полями в GlobalUser.
Для етого в User пишем чтото типа
return $this->p_pname;
}
echo $user->pname
и получу значение из $user->p_pname
С предыдущим кодом какбы совместили если б не приведения типов о котором я спрашивал.
public $global_user; // агрегированый глобальный юзер
private $refClass; // ревлектор для глобального юзера
private $nativeRefClass; // рефлектор для себя тоесть для потомка
// которым будет User Agent или Company
// нужно чтоб знать наш ли ето метод или метод агрегированого прокси
public function ProxyUser(){
parent::MLEntity(array());
$this->global_user = new GlobalUser();
$this->refClass = new ReflectionClass('GlobalUser');
// смотрим кто мы get_class($this)
$this->nativeRefClass = new ReflectionClass(get_class($this));
}
// нужно чтоб посмотреть наш ли псевдопроперти или агрегата
protected function is_native_property($Name){
return
$this->nativeRefClass->hasMethod('get_'.$Name) ||
$this->nativeRefClass->hasMethod('set_'.$Name);
}
function __set($Name, $Value){
if ($this->is_native_property($Name))
// если псевдопроперти наш то роботаем с ним через DictEntity MLEntity Entity
return parent::__set($Name, $Value);
else
// если не наш то передаем управление агрегату
return $this->__set_proxy($Name, $Value);
}
function __get($Name){
if ($this->is_native_property($Name))
return parent::__get($Name, $Value);
else
return $this->__get_proxy($Name);
}
function __call($Name, $Args){
$this->__call_proxy($Name, $Args);
}
function __set_proxy($Name, $Value)
{
if ($this->refClass->hasProperty($Name))
$prop = $this->refClass->getProperty($Name);
// если ето реальное поле то роботаем с ним
if ($prop && $prop->isPublic()){
$prop->setValue($this->global_user, $Value);
}
else {
// если ето не поле то наверное псевдопроперти и роботаем с ним
// если не псевдопроперти то ошибка вылезет внутри
return $this->global_user->__set($Name, $Value);
}
}
function __get_proxy($Name)
{
if ($this->refClass->hasProperty($Name))
$prop = $this->refClass->getProperty($Name);
if ($prop && $prop->isPublic()){
return $prop->getValue($this->global_user);
}
else {
return $this->global_user->__get($Name);
}
}
function __call_proxy($Name, $Args)
{
if ($this->refClass->hasMethod($Name))
$method = $this->refClass->getMethod($Name);
if ($method && $method->isPublic()){
return $method->invokeArgs($this->global_user, $Args);
}
else {
$this->global_user->__call($Name, $Args);
}
}
........................
}
public function User() {
parent::ProxyUser();
}
public function get_fname(){
return $this->p_fname;
}
fname - псевдопроперти которое связано с p_fname (тут p_ не от слова "пропертя" а от слова "персона")
Самого p_fname тоже нет. Оно будет доставаться из агрегата.
Если кому хватило терпения прочитать и понять, то я оч благодарен за внимание.
ЗЫ. ИМХО Ето у меня уже достаточно серйозний набор классов имеется. Подумываю может получится продать ну или хоть опенсурсом выложить. Только вот документацию писать лень.
PSS
Приводить ГлобалЮзера к Юзеру надо примерно так
$user = new User();
$user->global_user = $global_user;