Senior Software Developer (Kyiv)
Контакты

Достижения

Все достижения (4)

Наибольший вклад в теги

Все теги (20)

Лучшие ответы пользователя

Все ответы (33)
  • Какой таск-менеджер выбрать программисту?

    myrkoxx
    @myrkoxx
    developer
    Trello для начала будет норм. очень простой и можно кастомайзить
    Ответ написан
    1 комментарий
  • Symfony 2.6, как лучше обновится до современной версии?

    myrkoxx
    @myrkoxx
    developer
    В несколько этапов:

    1. Обновиться до 2.7
    2. Обновиться до 2.8
    3. Обновиться до 3.*

    Так делали на своем проекте и получилось проще чем сразу перескочить на 3.* . Слишком много изменений, а так пошагово уберёте deprecations и подготовите код к следующему шагу
    Ответ написан
    1 комментарий
  • Вопросы по ValueObject?

    myrkoxx
    @myrkoxx
    developer

    Ранее я делал это как отдельную сущность, строил связи Юзер -> Адрес, однако и при необходимости делал джойн.
    Однако, DDD позволяет добавить поле у юзера, и сделать его адресс ValueObject, так мы избегаем лишнего джойна и лишней выборке из лишней таблице.


    То что DDD позволяет, не значит что так и надо делать :)
    В одном "Страна, штат, город, зипкод, район, дом, квартира. " - может жить несколько человек. Если сохранить адрес как VO, c user`ами то места будет в базе использоваться больше. Также (с етим столкнулись как раз) - будут грузиться доп. поля. Я не знаю конкретно вашего контекста, но кажеться лучше все таки хранить адреса отдельно.

    А тепер по пунктам (так понял что пишете на php):

    1 - можно ли как то упустить ValueObject при загрузки Entity?
    - можно. Несколько способов (но лучше пересмотреть архитектуру):

    a) можна написать свой гидратор (не уверен в целесообразности) - docs.doctrine-project.org/projects/doctrine-orm/en...
    b) можна заюзать Partial Entity (не уверен в целесообразности) : docs.doctrine-project.org/projects/doctrine-orm/en...

    2 - как фильтровать наши сущности, если у нас там лежат обьекты а не простые поля типа string / integer? (Doctrine2 PhP)

    Вот конкртено для Doctrine2: docs.doctrine-project.org/projects/doctrine-orm/en...

    Пример (ReservationPeriod - ето ValueObject):

    class ReservationPeriod
    {
        private $from;
        private $to;
    
        public function __construct(\DateTimeInterface $from, \DateTimeInterface $to)
        {
            $this->from = $from;
            $this->to = $to;
        }
    
        public function from() : \DateTimeInterface
        {
            return $this->from;
        }
    
        public function to(): \DateTimeInterface
        {
            return $this->to;
        }
    }


    Вот наша entity:

    class Booking
    {
        private $id;
        private $meetingRoom;
        private $person;
        private $reservationPeriod;
        public static function byPerson(
            Person $person,
            MeetingRoom $meetingRoom,
            ReservationPeriod $reservationPeriod
        ): Booking {
            $self = new self();
            $self->id = new BookingId();
            $self->meetingRoom = $meetingRoom;
            $self->person = $person;
            $self->reservationPeriod = $reservationPeriod;
    
            return $self;
        }
    
        public function id(): ?BookingId
        {
            return (is_string($this->id)) ? new BookingId($this->id) : $this->id;
        }
    
        public function meetingRoom(): ?MeetingRoom
        {
            return $this->meetingRoom;
        }
    
        public function person(): ?Person
        {
            return $this->person;
        }
    
        public function reservationPeriod(): ?ReservationPeriod
        {
            return $this->reservationPeriod;
        }
    }


    Вот поиск по нашему ReservationPeriod:

    public function findByReservationPeriod(MeetingRoom $meetingRoom, ReservationPeriod $reservationPeriod): array
        {
            $queryBuilder = $this->createQueryBuilder('mrb');
    
            $queryBuilder
                ->orWhere(
                    $queryBuilder->expr()->andX(
                        $queryBuilder->expr()->eq('mrb.meetingRoom', ':meetingRoomId'),
                        $queryBuilder->expr()->between(':from', 'mrb.reservationPeriod.from', 'mrb.reservationPeriod.to')
                    )
                )
                ->orWhere(
                    $queryBuilder->expr()->andX(
                        $queryBuilder->expr()->eq('mrb.meetingRoom', ':meetingRoomId'),
                        $queryBuilder->expr()->between(':to', 'mrb.reservationPeriod.from', 'mrb.reservationPeriod.to')
                    )
                );
    
            $queryBuilder
                ->setParameters(
                    [
                        'meetingRoomId' => (string)$meetingRoom->id(),
                        'from'          => $reservationPeriod->from(),
                        'to'            => $reservationPeriod->to(),
                    ]
                );
    
            return $queryBuilder->getQuery()->getResult();
        }


    3 - наилучший способ валидации ValueObject?
    - думаю он сам должен себя валидировать. Я не даю возможности создать не валидный VO. Нужные для создания данные валидирую в констукторе VO. Примитивный пример:

    class NameValueObject
    {
        private $name;
        public function __construct(string $name)
        {
             if ($name === 'admin') {
                  throw new ReservedNameUsageException()
             }
         }
    }


    4. Возможно стоит использовать UserAddress как отдельную сущность, для ведения статистики и т.д. и т.п.?
    - Возможно. Нужно учитывать ваш контекст.

    5 - И что на счет таких полей как UserEmail, а надо ли делать его, email как ValueObject? Что это даст?
    - опять таки нужно учитывать ваш контекст. Что даст? VO сами по себе могут сделать удобнее работу и инкапсулировать в себе поведение, также они как правило immutable что тоже немало облегчает жизнь.
    Пример того как может виглядить такой VO:

    class EmailVO
    {
        private $emailAddress;
    
        public function __construct($emailAddress)
        {
            $this->validate($emailAddress);
    
            $this->emailAddress = $emailAddress;
        }
    
        public function getDomainName()
        {
            list (, $domain) = explode('@', $this->emailAddress, 2);
    
            return $domain;
        }
    
        public function getLocalName()
        {
            list ($email, ) = explode('@', $this->emailAddress, 2);
    
            return (string) $email;
        }
    
        public function equals(EmailVO $object)
        {
            if (!($object instanceof $this)) {
                return false;
            }
    
            /** @var EmailVO $object */
            return $this->emailAddress === $object->emailAddress;
        }
    
        protected function validate($emailAddress)
        {
            if ('' === $emailAddress) {
                throw new EmailAddressException('This value should not be blank.');
            }
            if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
                throw new EmailAddressException('This value is not a valid email address.');
            }
        }
    }


    6 - Что на счет таких полей как boolean и itneger? К примеру UserIsVerified и UserRating? Как правильно тогда строить запросы, статистику кто активирован и рейтинги?

    - тут надо по подробней. В чем проблема строить запросы, статистику кто активирован и рейтинги?
    Я б сделал не bool property UserIsVerified а возможно entity или VO в котором хранил бы дату верификации, возможно того кто верифицировал и способ верификации (нужно исходить от задачи)
    То же и с рейтингом (опять же исходить из требований надо) кто дал рейтинг, когда, какая оценка по вашей шкале, и суммировал их все

    7 - Стоит ли вообще трогать id и делать из него UserId? Или оставить autoincrement?
    - надо понимать надо ли оно Вам
    Ответ написан
    3 комментария
  • Doctrine - структура БД для хранения документов, и участников документооборота?

    myrkoxx
    @myrkoxx
    developer
    чисто мое ИМХО в разрезе Symfony я никогда не стал бы проектировать сначала схему базы. Всегда начинаю с создания мапинга Doctrine. Вот как пример (очень простой)

    BlogBundle\Entity\Blog:
      type: entity
      table: bb_blog
      repositoryClass: BlogBundle\Entity\Repository\BlogRepository
      fields:
          name:
              type: string
              length: 100
              nullable: false
          status:
              type: string
              length: 10
              nullable: false
      manyToOne:
          user:
              targetEntity: BlogBundle\Entity\User
              joinColumn:
                  name: user_id
                  referencedColumnName: id
      oneToMany:
          posts:
              targetEntity: BlogBundle\Entity\Post
              mappedBy: blog
              orderBy: { 'createdAt': 'ASC' }
              cascade:
                  - remove


    А потом уже с помощью DoctrineMigrationsBundle генерю миграции которые приведут базу в необходимое состояние.
    Ответ написан
    2 комментария

Лучшие вопросы пользователя

Все вопросы (3)