Ответы пользователя по тегу Symfony
  • Как добавить ключ в Symfony/Doctrine (миграция)?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Вы проделываете много работы магическими генерирующими командами, игнорируя результат (сами файлы мигарций и их инструкций)

    У вас не проходит одна миграция — видимо, вы ее уже пытались выполнить, выполнилась част ьпо созданию таблицы и все упало. Надо фиксануть руками — сравнить миграцию и состояние БД и все наладить.

    Тут еще подводный камень, тк миграция старая ен выполнена, то возможно, чт ов ней часть иснтрукций будет конфликтовать с последующими генерациями, которые вы генерируете — тк состав миграции не смотрит на инструкции в предыдущих, а просто на основании схемы в БД и в коде. Тогда как старая битая миграция имеет часть инструкций, которые сломают схему БД к моменту работы следующей

    Совет: просто посмотрите, чего не работает миграция, приведите БД руками к нужному состоянию или миграции к новому виду.
    Ответ написан
    Комментировать
  • Как обновить вложенный объект в doctrine?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Да, ваши поля сущности должны быть иммутабельными, чтобы все корректно работало.
    Делать поле иммутабельным и работать с сущностью через иммутабельность — есть элегантный способ

    // Вариант 1
    $user->setCounter(clone $user->getCounter());


    Доработайте в
    $user->raiseCount();

    // User.php
    
    public function raiseCount(): void
    {
         $this->counter = $this->counter->add();
    }


    // Counter.php
    
    public function add(): self
    {
         $self = clone $this;
         ++$self->value;
    
         return $self;
    }
    Ответ написан
    Комментировать
  • Как в Symfony преобразовать строку вида prop.prop[3].prop в строку [prop][prop][3][prop]?

    Maksclub
    @Maksclub
    maksfedorov.ru
    В Laravel есть такая Arr:undot()
    https://github.com/laravel/framework/blob/8.x/src/...

    Вы можете подтянуть хэлперы через композер от туда, тогда так юзать:
    use Illuminate\Support\Arr;
     
    $array = [
        'user.name' => 'Kevin Malone',
        'user.occupation' => 'Accountant',
    ];
     
    $array = Arr::undot($array);
     
    // ['user' => ['name' => 'Kevin Malone', 'occupation' => 'Accountant']]


    или сделать свою такую же
    Ответ написан
    Комментировать
  • Можно ли использовать condition в Роутинге чтоб получить значение метода Entity в Symfony?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Если вы про параметр метода контроллера (BlogPost $blogPost), то нельзя
    Тк роутинг уже отработал (с condition вместе) и когда уже работает ArgumentResolver — это уже др lifecycle приложения

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

    Если вы хотите 404 отдавать — проще проверку статуса поместить внутрь контроллера, это правда проще и удобнее
    Ответ написан
    Комментировать
  • Как сделать запуск крона по расписанию, указанному вручную?

    Maksclub
    @Maksclub
    maksfedorov.ru
    В `symfony` есть mybuilder/cronos-bundle, но есть ли возможность,чтобы время исполнения задач брать из таблицы-сущности `cron`?


    Данный бандл работает так:
    - команда парсит аннотации команд
    - вносит в крон расписание

    Вы можете изменить команду, которая бы не просто парсила аннотации, а ходила бы в БД и брала данные для них (скорее всего нужна будет своя анноатция)
    Ответ написан
    4 комментария
  • Как отрефакторить классы с неоднородными конструкторами?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Обычно делают REgistry

    FooInterface

    Service1Foo
    Service2Foo
    Service3Foo

    FooRegistry через теги или через call регаются конкретные сервисы, в фабрике получаем через type (если через call регали с нужным ключом) или в цикле прогоняя каждую зависимость и вызывая supports($type) у каждого из сервиса
    Ответ написан
    Комментировать
  • Как исправить Ошибку авторизации?

    Maksclub
    @Maksclub
    maksfedorov.ru
    UserInterface подразумевает, что массив строк (ролей) вернется

    либо отвяжите вашего юзера от UserInterface (я так и сделал), либо делайте так, как того требует интерфейс
    Ответ написан
    Комментировать
  • Отделение бизнес логики от фреймворка Symfony?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Генератор — просто инструмент для помощи, по итогу сущности чисты, не считая аннотаций/атрибутов для маппинга в ORM, но это просто мета-информации и завязка не существенна (не считая маленького компромисса с ArrayCollection). То есть если вы выберите др ORM, то эти аннотации вам не помешают никак, просто лишние заюзанные классы аннотаций

    Имея сущности доктрины — у нас не связанный от фреймворка код, пишите спокойно бизнесуху, не обращая внимания на то, как оно потом маппится. То есть практически все по каннонам

    Чтобы отделить репозиторий от домена — просто в домене делайте интерфейс, а вот реализация этого репозитория будет в Infrastrucure Layer, но это избыточно... риск минимальный, если сделаете не совсем по канону, а именно риск стоит как основной аргумент такового отделения (не просто же вы словам следуете, а причину понимаете?)
    Разработка строится на компромисах, если смените доктрину на др ORM — так и так писать новые репозиторий, вероятность низкая и многие например не делают такие интерфейсы — слишком усложнит код...
    Вам надо будет просто репозиторий в маппинге ORM\Repository заменить в таком случае

    Некоторые компании пишут интерфейсы и сильно усложняют код, но тк риск минимальный изменений, то такое усложнение приводит как правило к усложнению и не более. Следуйте здравому смыслу.
    Мой довод нельзя раскручивать "ну раз минимальный, то завяжусь по полной". Все же отделение логики надо делать

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

    617588c41bdde421641847.png
    Ответ написан
    8 комментариев
  • Как инициализировать маршрутизатор Symfony в проекте?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Вам надо поставить еще пару пакетов:
    symfony/config
    symfony/cache
    doctrine/annotations


    по сути с конфигом вы почти симфони заведете в стандартной установке, не считая Request/Response из Symfony Foundation... уже тогда симфу и ставьте

    можете взять пакеты попроще, типа Aura/Slim, там при регистрации приложения просто добавляются новые роуты
    Ответ написан
  • Чем отличается EntityManager->clear() от Doctrine->resetManager()?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Я вспомнил, течь в Доктрине может из-за SQL Logger, который в Connection
    Когда вы делаете resetManager() — вы убиваете и этот SQL Logger с его объектами в памяти

    Вам нужно сделать что-то типа
    $this->em->getConnection()->getConfiguration()->setSQLLogger(null);


    Это можно сделать на уровне настройки всего контейнера или сервиса, или в команде
    Но попробуйте для начала в своей консольной команде!
    Ответ написан
    Комментировать
  • Почему при тестировании symfony не отрабатывает аутентификатор?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Решение

    $this->client->request('GET', self::API_PREFIX . '/account/userinfo', [
                    'Authorization' => 'Bearer ' . $token,
            ]);


    замените на
    $this->client->request(
        method: 'GET', 
        uri: self::API_PREFIX . '/account/userinfo',  
        server: ['HTTP_Authorization' => 'Bearer ' . $token,]
    );


    Пруфы:
    https://github.com/symfony/symfony/issues/5074
    https://github.com/symfony/browser-kit/blob/5.3/Ab...
    Ответ написан
    1 комментарий
  • Class Table Inheritance - Querying Inherited Classes по полям Inherited сущности?

    Maksclub
    @Maksclub
    maksfedorov.ru

    Решение не заработает, тк поиск будет по полю родительской сущности
    $qb->expr()->andX(
        $qb->expr()->andX(
            $qb->expr()->isInstanceOf('sub1',  'TargetClass'),
            $qb->expr()->eq('sub1.sub1Field',  $sub1FieldValue)
        )
    );



    UPD2 (рекомендация): Не решать такие задачи через ORM, а делать просто SQL.

    UPD1: решение без instanceOf().
    Можно найти решение по красивее, но вот на коленке
    • Код не идеальный, но работает, как вариант
    • Можно выражения (равенство, <> и прочее тоже вынести на уровень передачи параметра)
    • Или заменить на вида Expr\Andx(), что даст много гибкости
    • Ну и проверок добавить


    Сущности:

    /**
     * @ORM\Entity
     * @ORM\InheritanceType("JOINED")
     * @ORM\DiscriminatorColumn(name="discr", type="string")
     * @ORM\DiscriminatorMap({"cat" = "Cat", "dog" = "Dog"})
     *
     * @ORM\Entity(repositoryClass="AnimalRepository")
     */
    class Animal
    {
    	/**
    	 * @ORM\Id
    	 * @ORM\Column(type="integer", nullable=true)
    	 * @ORM\GeneratedValue(strategy="AUTO")
    	 */
    	public ?string $id = null;
    }
    
    
    /** @ORM\Entity */
    class Cat extends Animal
    {
    	/**
    	 * @ORM\Column(type="string")
    	 */
    	public $meow;
    }
    
    
    /** @ORM\Entity */
    class Dog extends Animal
    {
    	/**
    	 * @ORM\Column(type="string")
    	 */
    	public $woof;
    }



    Repository:

    class AnimalRepository extends EntityRepository
    {
    	/**
    	 * @param array $filters
    	 *
    	 * @return \Generator<Animal::class>|Animal[]
    	 */
    	public function filter(array $filters): \Generator
    	{
    		foreach ($filters as $filter) {
    			[$entityClass, $conditions] = $filter;
    
    			if (!is_a($entityClass, Animal::class, true)) {
    				throw new \LogicException('Класс должен быть ребенком ' . Animal::class);
    			}
    
    			yield  from $this->getSubEntities($entityClass, [$conditions]);
    		}
    	}
    
    	private function getSubEntities(string $subEntityClassName, array $conditions): \Generator
    	{
    		$qb = $this->getEntityManager()->createQueryBuilder();
    		$qb->select('e')->from($subEntityClassName, 'e');
    
    		foreach ($conditions as $condition) {
    			[$param, $paramValue] = $condition;
    
    			$qb
    				->andWhere("e.$param = :$param")
    				->setParameter($param, $paramValue);
    		}
    
    		foreach ($qb->getQuery()->getResult() as $entity) {
    			yield $entity;
    		}
    	}
    }


    Тест (проходит)
    class AnimalRepositoryCest
    {
    	/** @var EntityManagerInterface */
    	private $em;
    
    	public function _before(FunctionalTester $I): void
    	{
    		$this->em = $I->grabService('doctrine.orm.entity_manager');
    	}
    
    	public function testSuccessFilter(): void
    	{
    		$cat1 = new Cat();
    		$cat1->meow = 'meow1';
    
    		$cat2 = new Cat();
    		$cat2->meow = 'meow2';
    
    		$dog1 = new Dog();
    		$dog1->woof = 'woof1';
    
    		$dog2 = new Dog();
    		$dog2->woof = 'woof2';
    
    		$this->em->persist($cat1);
    		$this->em->persist($cat2);
    		$this->em->persist($dog1);
    		$this->em->persist($dog2);
    		$this->em->flush();
    
    		/** @var AnimalRepository $animalRepository */
    		$animalRepository = $this->em->getRepository(Animal::class);
    		assertInstanceOf(AnimalRepository::class, $animalRepository);
    
    		// этот код можно в репозитории сокрыть
    		$resultIter = $animalRepository->filter([
    			Cat::class, [['meow' => 'meow2']],  // тут точка расширения гибкости добавления условий, чтобы все не только eq() было
    			Dog::class, [['woof' => 'woof1']],
    		]);
    		$result = iterator_to_array($resultIter);
    		assertCount(2, $result);
    
    		assertInstanceOf(Cat::class, $result[0]);
    		assertSame('meow2', $result[0]->meow);
    
    		assertInstanceOf(Dog::class, $result[1]);
    		assertSame('woof1', $result[1]->woof);
    	}
    }

    Ответ написан
  • Фиктивная сущность phpunit?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Зачем вам фиктивная, если в тесте вам нужна обычная сущность ? :)
    НЕ совсем понятен вопрос, нужна User — берите User
    Ответ написан
    3 комментария
  • Как сделать общий сервис во всех контроллерах?

    Maksclub
    @Maksclub
    maksfedorov.ru
    будут использовать __construct, то мне нужно будет дублировать все аргументы конструктора

    В каждом контроллере свои зависимости и это хорошо,
    если что-то продублировалось — это случайность, ну точнее это не дубль в классическом понимании, тут логика не дублируется
    Ответ написан
  • Зачем у одного пользователя много ролей?

    Maksclub
    @Maksclub
    maksfedorov.ru
    В итоге я получу вот такую бороду.
    0: "ROLE_ADMIN"
    1: "ROLE_OPERATOR"

    Не имеет значение, он оператор или он админ
    Имеет значение — может ли он выполнять операторский функционал (имеет роль оператора) или нет
    Также к др действиям: может ли он добавлять пользователей? Допустим имеет роль ROLE_ADMIN и для ROLE_ADMIN разрешено редактирвоать юзеров — в этом контексте он админ значит
    Ответ написан
    Комментировать
  • Вызвать commandBus один раз?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Сделайте команду, в которой будет пачка других команд
    И сделайте лисенер, который сможет ее обработать

    И тогда один раз: в цикле мини-команды собираете в пачку-команду, после хэндлите
    Ответ написан
    Комментировать
  • Как можно модифицировать response JWTAuthenticationBundle?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Ответ написан
    Комментировать
  • Можно ли программно создать DTO и провалидировать его?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Бывают разного рода задачи, когда строятся DSL и приходится динамически создавать правила и объекты
    Все зависит от ситуации и выбранного решения в реакцию на нее

    Валидация ответов в данном случае будет зависеть от того, какой тип при создании вопроса будет выбран/сконструирован. Вот под эти правила и нужно вам делать валидацию, кажется тут не будет конечных ДТО, только промежуточные
    Ответ написан
    Комментировать
  • Как в Doctrine, в DBAL указать PDO::ATTR_PERSISTENT => true?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Ентити-менеджер использует один объект Connection, Connection использует объект PDO, всегда везде одно подключение и работает во всем жизненном цикле приложения, в этом и суть работы (ну в том числе) DI контейнера — отдавать один и тот же объект и не плодить их. То есть на жизненный цикл приложения все и так работает

    Тесты функциональные? Может плодится много http запросов в разных процессах? Но если и так — то все равно процессы разные и объекты PDO разные, так что ваша настройка не сработает, тк просто сами приложения будут разные...

    Для таких случаев в Codeception есть такая штука как persistService, по идее сервис (в вашем случае EntityManager, если через него работаете, или Connection, если через DBAL работаете) должен один идти через эту штуку единый, даже если разные http запросы
    https://codeception.com/docs/modules/Symfony#persi...

    Крч, раскройте немного деталей ваших тестов и ситуации, может я все не туда пишу
    Ответ написан