Объекты справочники, Граф объектов

a.dobrynin

Новичок
Всем доброго времени суток.
Есть такая задача:
в системе заводится некая фирма (ООО "А"), фирме присваивают некие контакты (+7-123-456-7890, [email protected], [email protected]), каждый контакт имеет свой тип (контактный телефон, e-mail, jabber)

PHP:
class Firm {
    protected $_contact = array();
    protected $_name = '';
    public function setContact ($contact) {
        $this->_contact[] = $contact;
        return $this;
    }
}

class Contact {
    protected $_type = null;
    protected $_value = '';
    public function setType ($type) {
        $this->_type = $type;
        return $this;
    }
}

class ContactType {
    protected $_contact = array();
    protected $_name = '';
    public function setContact ($contact) {
        $this->_contact[] = $contact;
        return $this;
    }
}
1. каждая фирма содержит набор контактов
2. каждый контакт принадлежит только одному типу
3. каждый тип контактов содержит набор контактов

1. при создании фирмы создаются контакты
2. при создании контакта создаётся/берётся имеющийся тип

получаем некий граф, где у контакта есть два родителя, контакт создаётся через фирму, а тип необходимо подключить каким-то хитрым образом, причём тип не зависит от контакта

Уважаемые, Гуру, помогите найти решение прокси класса, который при создании типа либо подставлял имеющийся тип, либо создавал новый
P.S. в течении работы над типом тоже могут производиться операции, которые
должны приводить к изменениям у всех зависимых контактов (например email поменяли на МЫЛО)
необходимое и важное условие - конструктор не принимает параметров.
 

a.dobrynin

Новичок
некоторые соображения по теме:
создать прокси класс, который будет содержать ссылки на все созданные эл-ты и проверять уникальность нового объекта.

PHP:
class Proxy {
	protected static $_array = array();
// Installation - интерфейс
	public static function set($type, Installation $item) {
// если нет ещё ни одного эл-та, то нужно создать и вернуть ссылку на этот эл-т
		if (!isset(self::$_array[$type])) {
			self::$_array[$type] = array($item);
			return $item;
		} else {
// пытаемся найти равный в уже имеющемся списке
			foreach (self::$_array[$type] as $my_item) {
				if ($item->equal($my_item)) {
					return $my_item;
				}
			}
// если не нашли то заносим в список
			self::$_array[$type][] = $item;
			return $item;
		}
	}
	
	public static function get($type) {
		if (isset(self::$_array['type'])) {
			return self::$_array['type'];
		} else {
			return array();
		}
	}
	
	public static function test() {
// проверяем каждый тип
		foreach (self::$_array as $type) {
// и сравниваем все эл-ты между собой
			foreach ($type as $key1 => $item1) {
				foreach ($type as $key2 => $item2) {
					if ($key1 < $key2 && $item1->equal($item2)) {
// при равенстве любых из них удаляем последний
						unset(self::$_array[$key2]);
					}
				}
			}
		}
	}
}

проблемы:
1. при проверке двух новорождённых объектов класс скажет что они равны и даст ссылку на один и тот же объект то, хотя из них мы потом будем ПЫТАТЬСЯ создать разные объекты.
2. при создании нового пустого эл-та, он при сравнении с остальными эл-тами не даст результата и внесётся как уникальный, а потом может стать равным какому-либо
3. при тестировании массива нужно как-то корректнее удалять эл-ты, что бы все ссылающиеся на эти объекты переменные переопределились на новую ссылку
может кто-то подскажет как решить хотя бы одну из вставших пере до мной проблем?
 

Sokil.Dmytro

Новичок
а не слишком ли перемудрено делать классом тип контакта? может не стоит делать абстракцию настолько абстрактной?
 

a.dobrynin

Новичок
в данном случае это всего лишь упрощённый пример, но если дело пошло на то, то контакт может принадлежать:
1. фирме
2. персоне для контактов (системный администратор обслуживает несколько фирм)
3. зданию (например вахта, обслуживающая несколько фирм и производящая переадресацию, тогда поменяв в одном месте мы меняем у всех)
4. и мало ли к чему ещё можно привязать сущность контакт.

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

Духовность™

Продвинутый новичок
Ерунда с контактами и типами.
Тип контакта - это класс "мыло", "телефон", "почтовый адрес". Это класс, наследуемый от базового абстрактного класса "контакт". Этого достаточно, что бы не городить такие премудрости.

P.S. в течении работы над типом тоже могут производиться операции, которые
должны приводить к изменениям у всех зависимых контактов (например email поменяли на МЫЛО)
был человек, а стал дождевым червем? Шаманство какое-то...

Всё ИМХО
 
  • Like
Реакции: AmdY

a.dobrynin

Новичок
есть зерно истины в этих словах, но я вижу более широкое использование данных методов.
например нужно разослать сообщения по email, таким образом мы берём тип e-mail и рассылаем, таким образом отсекая все оставшиеся варианты.
предвидя вопрос связанный с
PHP:
class Contact_Email extends Contact {
}
сразу скажу, что типы могут расширяться (появляться) через UI (админку)

а вот делать доп поле описывающее тип контакта - лишает нас волшебной возможности разом отсекать всё ненужное и приводит к перебору всех контактов.

был человек, а стал дождевым червем? Шаманство какое-то...
=)
что-то в том духе, но я имел ввиду о используемой терминологии, всем нравится по разному:
1. E-mail
2. email
3. мыло
4. емэил
5. электронная почта
и т.д.
 

Духовность™

Продвинутый новичок
например нужно разослать сообщения по email, таким образом мы берём тип e-mail и рассылаем, таким образом отсекая все оставшиеся варианты
И что? Тип объекта, наследованного от "контакт", можно узнать через instanceof или ввести метод getType(), который бы возвращал строку "phone", 'mail' и т.д.

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

a.dobrynin

Новичок
как можно использовать метод instanceof или ещё что либо, если заранее не известно, сколько будет типов, ведь их расширяют через БД, программист не должен под каждую новую запись в таблице создавать соответствующий класс.

P.S. задача гораздо шире чем приведено в примере (и вообще, пример надуманный)
 

craz

Нестандартное звание
А что мыло у нас уже может выглядеть как +7 (495) 567-89-90 ? или телефон [email protected]? по-моему надуманная задача вы же можете определить из таблицы

id idPerson contacts
1 1 +7 (495) 567-89-90
2 1 [email protected]
3 1 ул. Уличная, д. 17

Типы этих контактов можно легко узнать по их внешнему виду.
 

a.dobrynin

Новичок
id idPerson contacts
1 1 +7 (495) 567-89-90
2 1 [email protected]
3 1 ул. Уличная, д. 17

Типы этих контактов можно легко узнать по их внешнему виду.
кто сказал, что [email protected] - это e-mail, а не jabber?
или 1-234-567 - это телефон, а не факс?
или вообще 1234567 - это может быть что угодно, даже icq

а вот таблиц вида (id idPerson contacts) я не создаю из соображений расширяемости, у меня немного др. вид:
(id contact typeId), (idPerson, idContact)
а можно и через наследование в БД =)
 

a.dobrynin

Новичок
а для вывода в UI очень удобно группировать
фирма ООО "А"
e-mail
[email protected]
[email protected]

телефон
123-45-67
765-43-21


и не приходится метаться по всему списку контактов и искать тот у кого в атрибуту type стоит e-mail
 

Вурдалак

Продвинутый новичок
в данном случае это всего лишь упрощённый пример, но если дело пошло на то, то контакт может принадлежать:
1. фирме
2. персоне для контактов (системный администратор обслуживает несколько фирм)
3. зданию (например вахта, обслуживающая несколько фирм и производящая переадресацию, тогда поменяв в одном месте мы меняем у всех)
4. и мало ли к чему ещё можно привязать сущность контакт.

поэтому логично создать абстрактную сущность
— т.е. ты городишь две таблицы вместо одной с доп. полем type только из-за того, что гипотетически один и тот же контакт может принадлежать и фирме, и Тане? Это как? Телефон может быть зарегистрирован сразу на юридическое и физическое лица? Или до 8-ми часов с некоего номера ICQ сидит работник конторы, а после — частное лицо? Или email используется сразу фирмой и дядей Ваней?

По-моему, раз уж хочется позволить добавлять несколько однотипных контактов, то ничего лучше двух таблиц
Код:
firm_contact { firm_id, contact, type }
Код:
person_contact { person_id, contact, type }
не придумать.
 

a.dobrynin

Новичок
1.
в данном случае это всего лишь упрощённый пример
и к контактам там отношения никакого нет, просто очень удачный аналог, который дерево из 20-ти объектов переводит в 3
2. отвечаю на вопрос Вурдалак
появляется новая сущность, которая будет иметь контакты, и что вы будете делать? создавать новую таблицу контактов? а я создам новую привязку и буду хранить контакт в той же таблице. (я не привязываю один контакт к двум сущностям).
описываю ситуацию:
звонок к вам на мобильный -> определяется номер телефона.
женский голос говорит, что встреча переносится на 17:00. и бросается трубка.
в какой таблице вы будите искать этот номер телефона, что бы понять какая же встреча переносится? я в одной =) потом произведя все необходимые JOIN
left join firm_contact on (...)
left join firm on (...)
left join person_contact on (...)
left join person on (...)
left join VAHTA_contact on (...)
left join VAHTA on (...)
я получу ответ на свой вопрос без всяких UNUON

Но вопрос не в целесообразности, а в способах реализации
 

Вурдалак

Продвинутый новичок
a.dobrynin, понимаешь, судя по реакции публики, пример как раз неудачный. Либо описан неудачно.

Вот ты пишешь:
в течении работы над типом тоже могут производиться операции, которые
должны приводить к изменениям у всех зависимых контактов (например email поменяли на МЫЛО)
.
— какие ещё изменения у зависимых контактов? Поменяли имя типа контактов. Всё.

PHP:
class ContactType {
    protected $_contact = array();
    protected $_name = '';
    public function setContact ($contact) {
        $this->_contact[] = $contact;
        return $this;
    }
}
— откуда тут setContact()? У типа нет контактов: это у контактов есть тип.

Касаемо хранения контактов скорее оказался прав ты.
 

a.dobrynin

Новичок
не буду спорить о удачности примеров

с одной стороны логично, что контакт содержит тип, но предположим есть такая задача (как было описано выше) сгруппировать контакты по их типам:
1. бегаем по всем контактам фирмы и если это почтовый адрес, то ставим в одном месте, телефон в другой и т.д. - на мой взгляд не очень удобно
2. берём тип контакта почтовый адрес и распечатываем содержимое, аналогично и все остальные - это гораздо удобнее, а когда дерево состоит из 20 объектов (а не 3-х как в нашем примере) то многие вопросы решаются проще.

ещё один аргумент:
пользователь создаёт набор контактов, которые ожидает сохранить (в этом наборе появляется доселе неизвестный нам тип контакта, который должен будет записаться в справочник и в дальнейшем использоваться), после применения метода save к фирме производится пробег по всем дочерним эл-там и их сохранение, а вот если тип зависит от контакта, то новый тип может сохраниться не один раз, а если он будет создан единожды, то к нему привяжутся все необходимые контакты и он сохранится только 1 раз.
+
перед сохранением контакта необходимо сохранить его тип т.к. контакт обязан содержать ссылку на id своего типа.

как-то замудрёно объяснил :(
 

a.dobrynin

Новичок
это совсем не удобно, особенно при большой вложенности эл-тов (да, я знаю как пользоваться стандартными функциями сортировки с пользовательскими требованиями описанными в своей функции :) - какой-то злой смайлик получается )

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

при такой логике, как организовать отношение этих двух эл-тов? фирма принадлежит контакту? О_о (чёт меня прёт уже)
 

craz

Нестандартное звание
это совсем не удобно, особенно при большой вложенности эл-тов (да, я знаю как пользоваться стандартными функциями сортировки с пользовательскими требованиями описанными в своей функции :) - какой-то злой смайлик получается )

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

при такой логике, как организовать отношение этих двух эл-тов? фирма принадлежит контакту? О_о (чёт меня прёт уже)
id pid(parent id firms) contact type

в чем проблема та не понял? или правда прет?

кстати type я бы на вашем месте тоже хранил бы в отдельной таблице раз уж так все у вас сложно и надумано
 

a.dobrynin

Новичок
id pid(parent id firms) contact type

в чем проблема та не понял? или правда прет?

кстати type я бы на вашем месте тоже хранил бы в отдельной таблице раз уж так все у вас сложно и надумано
проблема не проектировании структуры БД - там всё замечательно и отлажено,
а в реализации объектов работающих с ней.
А именно кто от кого зависит и кто в дереве выше.
 
Сверху