Symfony Реализация сущности словаря на Симфони

bars80081

Новичок
Добрый день,

есть потребность в одной стандартной реализации (с которой, как я думаю, работает большинство), но не могу никак нормально гугел спросить. Всё подсовывает ссылки на генерацию сущностей, либо реализацию мультиязычности, либо просто словарь терминов. Прошу направить в нужное русло.

Есть потребность в СЛОВАРЕ - небольшой массив данных, который не имеет смысла реализовывать в виде таблицы в БД.

Пример:
допустим, у таблицы orders есть поле status int. В нём хранится значение 0, 1, 2, 3... , которое означает NEW, CANCEL, SELL, REFUND... . На странице заказа требуется выводить соответствующее значение "новый", "аннулирован", "продажа", "возврат"... , на странице списка заказов требуется выводить селектор для фильтрации, в API следует при выгрузке заказа выдавать соответствующее кодовое слово NEW, CANCEL, SELL, REFUND, а в выгрузке API по стандарту ГОС-ШМОС-ТЕЛЕРАДИО ОТ, АН, ПД, ВЗ.... и так далее.

руки чешутся написать два базовых класса Dictionary и DictionaryItem для реализации функционала и наследоваться от них для каждого случая словаря. В духе:
PHP:
class Dictionary {
    protected static $data = [];
    protected static $itemClass;
    public static function get($search, $by = 'id') {
        foreach(self::$data as $item) {
            if(isset($item[$by]) && $item[$by] == $search) {
                return new $itemClass($item[$by]);
            }
        }
        return new $itemClass();
    }
    public static function getList($by) {
        $data = [];
        foreach(self::$data as $item) {
            if(isset($item[$by])) {
                $data[] = $item[$by];
            }
        }
        return $data;
    }
    // разные полезные методы
}

class DictionaryItem {
    public function __construct($data) {
        if(!empty($data)) {
            foreach($data as $key => $v) {
                $this->set($key, $v);
            }
        }
    }
    // методы реализующие динамическое построение геттеров и сеттеров
}

class OrderStatusDictionary extends Dictionary {
    protected static $data = [
        [
            'id' => 0,
            'code' => 'NEW',
            'title_ru' => 'новый',
            'GOS_SHMOS' => 'ОТ',
        ],
        [
            'id' => 1,
            'code' => 'CANCEL',
            'title_ru' => 'аннулирован',
            'GOS_SHMOS' => 'АН',
        ],
        ...
    ];
}
class OrderStatusDictionaryItem extends DictionaryItem {
    protected $id = -1;
    protected $code = '';
    protected $title_ru = '';
    protected $GOS_SHMOS = '';
}
в конечном счёте это нам должно дать центральное хранилище для словаря, готовые фукции получения нужного кода по каком-то входящему параметру, готовые списки и удобное использование. к примеру, сущность Order можно было бы связать так, чтобы в twig вставлять требуемое значение без лишних действий {{ order.status.title_ru }}.

Почему не сделать такой словарь в виде таблицы в БД и не приложить к ней соответствующую сущность и репозиторий?
как-то кажется, что слишком жирно. словарь - это не данные, обновление или дополнение - практически никогда. зачастую имеет ничтожный перечень значений. обращаться в БД по такому случаю, городить здоровые сущности на каждый чих - как-то перебор. на практике, в моих проектах, в среднем на каждую сущность может потребоваться два-три словаря. хотя некоторые словари повторяются (к примеру, статус активности), но иметь ради таких маленьких перечней лишние 200-400 таблиц в БД как-то непонятно зачем.

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

WMix

герр M:)ller
Партнер клуба
у нас словарь в базе, ключ имеет вид ORDER.STATUS.NEW где ORDER.STATUS это пространство, а NEW слово.
в базе может быть слово переведено как NEW = 'новый' так и STATUS.NEW = 'новый' и ORDER.STATUS.NEW = 'новый' но сработает наиболее длинное совпадение.
весь словарь (на язык) вытягивается одним запросом, сериализируется в json, и будет использован исключительно на клиенте.
сервер использует словарь только для генерации email и pdf
 

bars80081

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

получилось так:

основа хранилища Dictionary:
PHP:
namespace App\Repository;

class Dictionary {
    protected static $primaryKey = 'id';
    protected static $term;
    protected static $data = [];
    public static function get($value = null, $field = null) {
        if(is_null($value)) {
            return new static::$term();
        }
        if(is_null($field)) {
            $field = static::$primaryKey;
        }
        foreach(static::$data as $item) {
            if(isset($item[$field]) && $item[$field] == $value) {
                return new static::$term($item);
            }
        }
        return new static::$term();
    }
}
основа сущности DictionaryItem:
PHP:
namespace App\Entity;

class DictionaryItem
{
    public function __construct($data = [])
    {
        foreach($data as $key => $value) {
            if(isset($this->{$key})) {
                $this->{$key} = $value;
            }
        }
    }
}
классы, которые их используют под себя:
PHP:
namespace App\Repository;

class LoadingStatusDictionary extends Dictionary {
    protected static $term = 'App\Entity\LoadingStatusDictionaryItem';
    protected static $data = [
        [
            'id' => 0,
            'code' => 'UNDEFINED',
            'titleRu' => 'неизвестно',
            'hexColor' => 'cccccc',
        ],
        [
            'id' => 1,
            'code' => 'ISSET',
            'titleRu' => 'имеется',
            'hexColor' => 'ff0000',
        ],
        [
            'id' => 2,
            'code' => 'SUCCESSFULL',
            'titleRu' => 'успешно',
            'hexColor' => '00ff00',
        ],
    ];
}
PHP:
namespace App\Entity;

class LoadingStatusDictionaryItem extends DictionaryItem
{
    protected $id = -1;
    protected $code = 'ERROR';
    protected $titleRu = 'ошибка';
    protected $hexColor = '000000';
    public function getId(): int
    {
        return $this->id;
    }
    public function getCode(): string
    {
        return $this->code;
    }
    public function getTitleRu(): string
    {
        return $this->titleRu;
    }
    public function getHexColor(): string
    {
        return $this->hexColor;
    }
}
сущность, которая использует словарь:
PHP:
namespace App\Entity;

use App\Repository\LoadingStatusDictionary;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping\ManyToOne;

/**
 * @ORM\Entity(repositoryClass="App\Repository\LoadingRepository")
 * @ORM\Table(name="loading")
 * @ORM\HasLifecycleCallbacks
 * @App\Entity\LoadingStatusDictionaryItem
 */
class Loading
{
    //...
    /**
     * @ORM\Column(type="integer", nullable=false, options={"default":0})
     */
    protected $status;

    /**
     * @var \App\Entity\LoadingStatusDictionaryItem
     */
    protected $statusDictionaryItem;

    public function __construct($id = null)
    {
        //...
        $this->setStatus(0);
    }

    /**
     * Set status.
     *
     * @param int $status
     *
     * @return Loading
     */
    public function setStatus($status)
    {
        $this->status = (int)$status;
        $this->statusDictionaryItem = LoadingStatusDictionary::get($this->status);

        return $this;
    }

    /**
     * Get status.
     *
     * @return int
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Get statusDictionaryItem.
     *
     * @return LoadingStatusDictionaryItem
     */
    public function getStatusDictionaryItem()
    {
        return $this->statusDictionaryItem;
    }
    //...
работает хорошо. особенно если сам создаю объект new Loading();
Однако, при заборе данных силами ORM, по инструкциям которые прописаны в аннотациях, в statusDictionaryItem оказывается null.
В принципе, можно перебороть проблему, если ввести в класс Loading метод
PHP:
    /**
     * @ORM\PostLoad
     * @ORM\PostPersist
     */
    public function fetchEntityManager($arg)
    {
        if(is_null($this->statusDictionaryItem)) {
            $this->setStatus($this->status);
        }
    }
но это жуткая заплатка.

своих мозгов при чтении документации не хватает, чтобы осилить, как правильно и что надо прописывать в аннотациях, дабы он сам брал стороннюю сущность (не связанную с БД) и забирал данные.
ладно, если бы ORM сопротивлялся бы работе со статическими методами или т.п., но не могу даже заставить обратить внимание на LoadingStatusDictionary или LoadingStatusDictionaryItem

может ткнёте в конкретное место документации?
 

WMix

герр M:)ller
Партнер клуба
>> protected $titleRu

Вот если «title» на язык, на строку записывать, кошерней будет
 
Сверху