• Почему когда подписываюсь на Doctrine.Events::preUpdate, он выполняется бесконечно?

    Frostealth
    @Frostealth
    Backend Developer
    Вызов flush() в процессе обработки preUpdate приводит к бесконечной рекурсии, ибо обработчик события вызывается в процессе выполнения предыдущего вызова flush().
    Цепочка вложенных вызовов в вашем случае выглядит следующим образом:

    - EntityManager::flush()
    - UnitOfWork::commit()
    - UnitOfWork::executeUpdates()
    - ListenersInvoker::invoke()
    - OrderEventSubscriber::preUpdate() - вызывается еще до обновления Order и его удаления из UnitOfWork
    - $this->notificationsCreator->createChangeStatusNotification() - создает рекурсию вызовом `flush()`
    - EntityManager::flush() - снова пытается обновить данные Order и вызывает обработку событий `preUpdate`
    - ...
    - EntityManager::flush()
    - ...

    Вызов методов persist(), remove() и т.п. в процессе обработки событий доктрины может привести к неожиданным результатам. Данные просто могут быть не сохранены, как минимум. Крайне не рекомендую менять какие-либо данные в Entity, EM/UoW при обработке событий доктрины.

    В вашем случае можно реализовать свое событие, например OrderStatusChanged. Но лучше использовать более конкретные события вроде OrderCompleted и OrderCanceled.
    И воспользоваться symfony/event-dispatcher.
    Либо создавать уведомление непосредственно там, где выполняете изменение статуса заказа (контроллер, сервис и т.п., зависит от вашей архитектуры) и вызывается flush().
    пример верного вызова

    $this->em->flush();
    $this->events->dispatch(new OrderCompleted($order->id));
    
    // или
    $this->em->flush();
    $this->notificationCreator->createChangeStatusNotification($order->getCustomer());



    P.S. Рекомендую использовать Guard Clauses для уменьшения вложенности и улучшения чтения кода.
    пример

    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getObject();
        if (!$entity instanceof Order) {
        	return;
        }
    
        $this->logger->info($entity);
        $onlyStatusChanged = count($args->getEntityChangeSet()) === 1 && $args->hasChangedField('status');
        if ($onlyStatusChanged) {
            $this->notificationsCreator->createChangeStatusNotification($entity->getCustomer());
        }
        // много кода...
    }

    Ответ написан
    1 комментарий
  • Как обновить приложение с Sympony 1.4 на последнюю версию?

    Stalker_RED
    @Stalker_RED
    Чисто в теории вы можете почитать гайды по апгрейду, и обновиться сперва на symfony2, потом с 2 на 3, потом на 4, и так далее, пока не дойдете до 7, к тому моменту она уже выйдет из бэты.

    На практике, проще будет переписать. Там слишком много отличий, в том числе довольно глубинных. Огромные шансы, что ваши бандлы (или как их там в 1.4, компоненты?) уже не поддерживаются, и придется подбирать альтернативу.
    Ответ написан
    Комментировать
  • Как вставить данные в БД из ajax?

    myks92
    @myks92 Куратор тега PHP
    Нашёл решение — пометь вопрос ответом!
    Вы сначала изучите Фреймворк. Сходите в документацию, прежде чем писать такой код. Например, зачем использовать такие конструкции $_POST['pages']; Так же для отладки используется не контроллер, а провайдер. И функции dump. Для симфони, как и для других это всё давно продумано.
    Ответ написан
    2 комментария
  • Что именно означает lazy в настройках SecurityBundle?

    myks92
    @myks92
    Нашёл решение — пометь вопрос ответом!
    Ленивый анонимный режим предотвращает запуск сеанса, если нет необходимости в авторизации (т.е. явной проверке привилегий пользователя). Это важно для обеспечения возможности кэширования запросов (см. HTTP-кэш).

    https://symfony.com/doc/current/security/.html#the...
    Ответ написан
    2 комментария
  • Как в в проекте симфони правильно указать папку public вкачестве стартовой?

    @dodo512
    Создать домен можно в ручном режиме.
    [Меню - Настройки - Домены] в качестве папки домена указать public.
    Ответ написан
    7 комментариев
  • Symfony, как лучше всего хранить класс в настройках, чтобы его зависимости были подгружены?

    BoShurik
    @BoShurik Куратор тега Symfony
    Symfony developer
    Из вопроса не очень понятно, но после обсуждения в комментариях стало ясно что нужен Service Locator
    https://symfony.com/doc/6.0/service_container/serv...
    App\handler\action\Handler:
        arguments: !service_locator
            type1: '@App\handler\create\Handler'
            type2: '@App\handler\upload\Handler'
    Ответ написан
    Комментировать
  • Какая админка наиболее оптимальна для Symfony?

    Sanes
    @Sanes
    Которую сам напишешь, та и будет оптимальной.
    Ответ написан
    5 комментариев
  • Можно ли и нужно ли и нужно ли выносить Symfony форму в сервис или её лучше оставить в контреллере?

    @Flying
    1. В Symfony best practicies рекомендуют, да
    2. Собственно см.п.1. В частности это улучшает поддерживаемость кода, особенно в случае более-менее сложных форм или форм, требующих дополнительной логики инициализации / конфигурирования. Собственно ваш код как раз и использует форму как сервис, попробуйте скопировать содержимое класса CandidateType сюда и сравнить полученный код.
    3. Код обработки формы скорее всего выносить в сервис не стоит т.к. он прямо завязан на преобразование Request => Response, а для этого контроллеры и существуют.
    Ответ написан
    Комментировать
  • Нужно ли генерировать отдельный бандл для Api в Symfony 5.2?

    myks92
    @myks92
    Нашёл решение — пометь вопрос ответом!
    Зачем вам бандл? Вы что планируете подключать этот код где-то в другом приложении? Бандл это по сути интеграция вашего кода с симфони приложением.

    Создавайте папку Api и туда помещайте. Можно сделать и отдельное приложение. Решать вам.

    Цитата из документации:
    В версиях Symfony до 4.0 было рекомендовано организовать собственный код приложения с помощью пакетов. Это больше не рекомендуется, и пакеты должны использоваться только для совместного использования кода и функций между несколькими приложениями.
    Пакет похож на плагин в другом программном обеспечении, но еще лучше. Основные функции Symfony framework реализуются с помощью пакетов (FrameworkBundle, SecurityBundle, DebugBundle и т. Д.) Они также используются для добавления новых функций в ваше приложение с помощью сторонних пакетов.
    Ответ написан
    Комментировать
  • Создание формы в одном месте - обработка в другом. Правильно ли это в Symfony?

    myks92
    @myks92
    Нашёл решение — пометь вопрос ответом!
    Формы нужны там, где человек через UI вводит данные. А в AJAX (он же API) данные прилетают не в форму, а обычным POST запросом, который обрабатывается. И если надо валидируется с помощью компонента.
    Ответ написан
    Комментировать
  • Правильно ли указывать foreach в репозитории в Symfony?

    @Flying
    Вам стоит взглянуть на различные режимы гидраторов в Doctrine. В частности в вашем случае вы, скорее всего захотите использовать scalar hydration по результатам выборки одного столбца. Вместе с этим режимом очень хорошо работает array_column(), так что ваш метод мог бы выглядеть примерно вот так (в примере идёт выборка столбца email из entity User):
    public function getEmails()
    {
        return array_column($this->getEntityManager()
            ->createQuery('select u.email from User u')
            ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR), 'u_email');
    }

    или, если вам, к примеру, необходима связь между id и email:
    public function getEmails()
    {
        return array_column($this->getEntityManager()
            ->createQuery('select u.id, u.email from User u')
            ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR), 'u_email', 'u_id');
    }
    Ответ написан
    Комментировать
  • Как подключить, настроить tunnel в browsersync gulp?

    ktim8168
    @ktim8168
    Frontend Developer
    Согласно документации, есть два варианта подключения. Если выставить true, генерируется какой-то случайный url, если передать строку, url формируется согласно этой строке
    // Tunnel the Browsersync server through a random Public URL
    // -> http://randomstring23232.localtunnel.me
    tunnel: true
    
    // Attempt to use the URL "http://my-private-site.localtunnel.me"
    tunnel: "my-private-site"

    Тебе остается только обновить функцию browsersync
    browserSync.init({
            server: { baseDir: 'app/' },
            notify: false,
            online: true,
            tunnel: "test", // или true если нужен рандомный туннель
            browser: "chrome",
        });

    Запускаешь gulp и в консоле смотри, какой у тебя туннель сформировался
    Ответ написан
    Комментировать
  • Как сохранить форму, в которую встроена коллекция другой формы?

    BoShurik
    @BoShurik Куратор тега Symfony
    Symfony developer
    По вашей же ссылке предлагается решение:
    // src/AppBundle/Form/CustomerType.php
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //....
        $builder
            ->add('phones',CollectionType::class, array(
                'by_reference' => false,
                // ...
            ));
        //....
    }


    class Customers implements UserInterface
    {
        /**
         * @ORM\OneToMany(targetEntity="AppBundle\Entity\Phone", mappedBy="customer_id", cascade={"persist", "remove", "merge"})
         */
        private $phones; // Это же коллекция, нужно множественное число, чтобы работали adder и remover
    
        public function addPhone(Phone $phone)
        {
            $phone->setCustomer($this);
            $this->phones->add($phone);
        }
    
        public function removePhone(Phone $phone)
        {
            $phone->setCustomer(null);
            $this->phones->removeElement($phone);
        }
    }


    // src/AppBundle/Form/PhoneType.php
    // $builder->add('customerId', HiddenType::class); // не нужен
    Ответ написан
    1 комментарий
  • Как переконфигурировать twig-шаблоны в Symfony 4?

    094ikis09
    @094ikis09
    Medium Rare
    Скорее всего twig закеширован - используйте команду в директории с проектом
    php bin\console cache:clear
    Или удалите директорию var/cache
    Ответ написан
    1 комментарий
  • Symfony - Repository Как избежать двойного кода в этом случае?

    Maksclub
    @Maksclub
    maksfedorov.ru
    flush() нужно вынести, потому что вы можете заперсистить 100 объектов и сделать один flush — одна череда обращений к Бд. В вашем же случае будет 100 и более обращений к БД

    Чтобы сделать универсальный метод для персиста в репозиториях, раз уж вы решили так делать (многие считают это верным) — можно сделать универсальный код (трейт к примеру), в котором будет проверка через classMetadata, что сохраняемый объект нужного типа для репозитория (тут не забываем про наследование сущностей, is_a()и вот это все) и если придет не тот объект — кидать InvalidArgumentException

    НО! Если вы репозитории размещаете в своем домене/пакете/неймпсейсе, то вам не избежать дублирования кода, и это не так уж и страшно... Связанность и паутина наследований страшнее. Репозиториев все равно мало во всем коде относительно всей базы кодовой.
    Ответ написан
    2 комментария
  • Зачем нужен fosrestbundle в symfony?

    @Flying
    FOSRestBundle упрощает создание REST endpoints, преобразовывая имена методов в роуты + беря на себя ещё ряд базовых функций по упрощению создания REST API на Symfony. К примеру вам ведь нужно выдавать нормальные ответы в случае ошибок и exceptions, а ошибки, они ведь очень разные бывают. Неприятно когда у тебя вроде бы REST API, а он вдруг начинает HTML рендерить.

    В целом, безусловно, всё это можно сделать и руками, но по сути в итоге что-то близкое и получится, ну может кроме роутинга.

    В целом FOSRestBundle не особо большой, в экосистеме Symfony есть гораздо более мощные решения для создания API
    Ответ написан
  • Как исправить ошибку 500, при загрузки сайта на Symfony?

    FoxCloud
    @FoxCloud
    Хостинг и облачные сервисы
    Здравствуйте!
    Для того, чтобы исправить 500 ошибку на сайте, сделайте следующее (от простого к сложному):

    1. Вспомните, что вы делали недавно на сайте и верните все как было.
    2. Восстановите сайт из резервной копии от числа, когда сайт ещё работал. Начните с восстановления файлов. Чаще всего это мжно сделать несколькими кликами в хостинг панели.
    3. Смените версию PHP для сайта. Попробуйте несколько версий. Если не поможет - верните на PHP версию, которая была.
    4. Убедитесь, что на хостинг аккаунте есть сводоное место любым знакомым вам способом.
    5. Обратитесь к хостинг компании за помощью. Иногда хостеры помагают с подобными проблемами на бесплатной основе.

    Сложнее:
    6. Проверьте логи на наличие ошибок. Логи можно найти в нескольких местах:
    1. Логи сервера, часто их можно найти:
    - в корне сайте, файл /error.log (CPANEL панель)
    - В директории /logs/Ваш_сайт.error.log (Панель ISPmanager5)

    2. Логи symphony
    Зайдите в корень сайта, а потом в /var/log/
    Там вы найдете логи.
    Проанализируйте логи, они наведут вас на проблему.

    7. Включите дебаг syphony.
    Инстуркция по ссылке: https://symfony.com/doc/4.2/components/debug.html

    И второй вариант - обратиться в тех-поддержку хостера. Обычно они помогают с установкой сайта.
    Ответ написан
    Комментировать
  • Где делать редирект?

    mad_maximus
    @mad_maximus
    $event->setResponse(new RedirectResponse(...));
    Ответ написан
    Комментировать
  • Как сделать Calc элементы в sass с переменными?

    delphinpro
    @delphinpro Куратор тега CSS
    frontend developer
    $h: percentage(1/3);
    width: calc(#{$h}  - 1px);
    Ответ написан
    5 комментариев