Люди. Подскажите.
Есть ИМ (на php) на с легаси, говном и костылями (переписывание согласовано и запланировано, ибо тупик). В нём, допустим, носки. У каждого носка, допустим, массив размеров. Нужно, допустим только в админке, оставить всё как есть, а вот для каталога носок с тремя размерами становится тремя разными носками. С разными айдишниками, страницами и так далее, но основной набор данных у них общий. И класс один и тот же (иначе костылять, неперекостылять).
[Примечание: в базе просто запилил табличку {origin_id, clone_id, size_id}]
И вот не знаю даже как это адекватно реализовать в плане ООП.
Порассуждаю прямо тут (может и отправлять не придётся):
Как минимум нам при работе с клонированием нужно не путать где клон, а где оригинал, дабы не настругать в базу говна. Значит это будет два разных класса-обёртки: клон и оригинал.
Оригиналу хорошо бы вообще самому позаботиться о том, чтобы его набор клонов (записи в таблице клонов и записи товаров, являющиеся этими клонами) был бы всегда корректным и актуальным. Тут охота запилить публичный маха-метод updateClones(), который бы удалил лишние, да создал недостающие, чтобы можно было дёргать его после сохранения в админке и всяких импортах (правда подозреваю что это не совсем гуд).
Это подразумевает наличие, возможно приватных, методов в роде getClones(), сloneExists(int size_id), makeClone(int size_id), getSizes(), getCloneIdBySizeId(int size_id), removeClone(int clone_id), clearClones(), может ещё каких-то.
Класс клона позволил бы... ну айдишник оригинала получить. А ещё айдишник размера.
Ещё нужен класс, который всё это объединит. Нет, не верно, нужно всё это объединить.
Например товар должен уметь определять не клон ли он. Нет. При сохранении товара нужно определить клон ли он. Для клона будет одна реализация сохранения, для оригинала другая (в т.ч. вызывающая обновление/сохранение всех клонов). Наверное логичнее всего это сделать не здоровенным if'ом в товаре, а поручить какому-то классу. Уверен что на это и паттерн есть (стратегия или что там). Но тут имеется ньюанс: вызывать сие должен товар (иначе тонну легаси переписывать). То есть во множестве мест вызывается GoodPage->save() (при том тот код может даже не знать что это GoodPage, ибо для него это просто всякие Page, та и фабрику которая это строит будет адски сложно заставить построить GoodClonePage и GoodOriginPage), так что в любом случае мы правим именно его реализацию. Пожалуй сделаю как проще и запилю там пару приватных методов cloneSave() и originalSave(), а в save() будет что-то такое:
if($this->isClone()) {
return $this->cloneSave();
} else {
return $this->originalSave();
}
И если уж понадобится это как-то изменить, то в любом случае править товар. Уровень его "божественности" это не изменит. Так ведь?
В итоге будем иметь что-то типа:
class GoodClone
{
public $good_id;
public $origin_id;
public $size_id;
public function remove()
{
(new GoodPage($clone->good_id))->remove();
$this->data->delete($good_id);
}
}
class GoodCloneOrigin
{
public $good_id;
public function updateClones()
{
foreach ($this->data->sizes as $size_id) {
if (!$this->cloneExists($size_id)) {
$this->makeClone($size_id);
}
}
//А при удалении размеров клон по внешнему ключу удалится.
//Хотя… «Клон» то да, а товар то не-а.
//Убрал внешний ключ. Вернее ON DELETE SET NULL
$deletedClones = $this->data->getClonesWhereSizeIsNull();
foreach ($deletedClones as $clone) {
$clone->remove();
}
}
}
class GoodPage extends Page
{
/* … */
//Здесь всё почти без изменений, кроме:
private function isClone();
private function saveClone();
private function saveOriginal();//отсюда будет вызов GoodCloneOrigin::updateClones()
public function save()
{
if ($this->isClone()) {
return $this->cloneSave();
} else {
return $this->originalSave();
}
}
}
https://gist.github.com/mkusher/66667736a20cb19cfa4d6476dda64d21 не? В админке Good, для каталога GoodItem