Yandex Message Queue в Symfony Messanger

В веб-приложениях часто требуется выполнять некоторые операции асинхронно. Для этого используются очереди сообщений. Можно использовать протокол AMQP, например RabbitMq или Kafka.

В рамках облаков часто используется Amazon SQS. В России же есть Yandex, который в рамках Yandex Cloud предоставляет сервис Message Queue, который является реализацией протокола Amazon SQS. Таким образом, инструменты разработчика от SQS подходят и для YMQ.

На данный момент в YMQ используется протокол на основе XML, который уже не используется в официальном SDK, там уже JSON, поэтому из коробки ничего не работает. Разработчики обещают обеспечить поддержку в будущем, но без указания сроков.

Для того что бы использовать Yandex Message Queue в Symfony Messanger требуется установить библиотеку для работы с SQS:

composer require symfony/amazon-sqs-messenger

Далее в .env:

MESSENGER_TRANSPORT_DSN=sqs://message-queue.api.cloud.yandex.net/<id>/<id>/<queueName>?access_key=<key>&secret_key=<secret>

Этот адрес можно взять в консоли управления Yandex Cloud.

Здесь:

id/id — это часть URL из консоли управления, key и secret — это статические ключи доступа для YMQ. Требуются права ymq.writer, ymq.reader

Если сейчас запустить вычитку очереди через php bin/console messanger:consume <название очереди>, то получим ошибку: 400 Bad request. Так происходит из-за того, что для обмена данными используется формат xml, а библиотека по умолчанию пытается использовать JSON.

Symfony для связи с AWS использует библиотеку AsyncAWS. Для SQS используется ее часть — async-aws/sqs. В версии 2.0 используется JSON, а вот в 1.9 — XML.

Для того, что бы Messanger использовал XML для коммуникации с SQS-совместимым сервисом нужно добавить явную зависимость на эту библиотеку:

composer require async-aws/sqs ^1.9

После этого YMQ через Symfony Messanger работает нормально

Как задавать права доступа в Symfony используя базу данных (Voters used database)

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

Использование Symfony Voters

Symfony использует Voters что бы определить доступ к URL и другим ресурсам. Множество voters которые входят в комплект поставки вместе с Symfony security  которые используют конфигурацию в security.access_control что бы определить нужно ли давать права на запрос или нет.

Continue reading

Как тестировать приватные сервисы в Symfony.

2 версии Symfony подвержены рассогласованностью между сервисами и тестами. Вы используете Symfony 3.4 или 4.0? Вы хотите тестировать сервисы, но не знаете как получить их правильно? Сегодня мы посмотрим на возможные решения.

Continue reading

Деревья в PHP + Twig 2.0

Предположим, есть задачка, вывести дерево.

Под рукой PHP, а как view — Twig.

Пусть структура данных на backend будет такой:

$tree = [

            [
                'name' => 'foo',
                'children' => [
                    [
                        'name' => 'bar',
                        'children' => [
                            [
                                'name' => 'baz',
                                'children' => [

                                ],
                            ],

                            [
                                'name' => 'baz',
                                'children' => [

                                ],
                            ],


                        ]
                    ]
                ]
            ]

        ];

Тогда простроить дерево можно так:

{% macro makeTree(node) %}
    {% import _self as self %}
    
  • {{ node.name }} {% if node.children|length %}
      {% for child in node.children %} {{ self.makeTree(child) }} {% endfor %}
    {% endif %}
  • {% endmacro %} {% from _self import makeTree %} {% if tree %}
      {% for node in tree %} {{ makeTree(node) }} {% endfor %}
    {% endif %}

    Получится вложенный список из ul и li.

    Миграция пользователей на безопасный алгоритм хеширования в Symfony

    Ваше приложение может использовать старый, небезопасный алгоритм хеширования для хранения пароля, такой как MD5 (без использования соли)

    Эта статья объясняет как преобразовать уже имеющиеся пароли, зашифрованные уязвимым алгоритмом в пароли зашифрованные с использованием безопасного метода хеширования (например с использованием Bcrypt )

    Что бы решить проблему, мы сделаем конвертацию на лету, когда пользователь успешно входит в систему. Будем использовать интерфейс EncoderAwareInterface

    login listener и использовать не очень хорошо известные параметры в security.yml.
    Continue reading

    ORDER BY RAND() in Doctrine without implement a new Doctrine function

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

    В MySQL эта задача решается очень просто:

    SELECT column FROM table
    ORDER BY RAND()
    LIMIT 10

    Но если вы используете DQL (Doctrine Query Language) это будет не так просто. Следуя документации вы можете реализовать расширение для Doctrine и добавить инструкцию RAND в запросы, но мы не будем этого делать.

    Для нашего решения мы будем использовать конструкцию where IN и будем искать что-нибудь (в данном случае ID или другое поле с автоинкриметом, если ваша таблица не содержит первичного ключа с автоинкриментом, вы должны реализовывать RAND расширение для Doctrine) в соответствии с случайными числами полученными при помощи простой функции на php.

    В данном примере, таблица имеет поле с автоинкриментом, которое называется id (которая содержит в себе числовые значения), что бы получить случайные записи нам нужно для начала создать функцию, которая возвращает случайные числа в заданном диапазоне (начальное значение, максимальное значение и количество), например, такую как эта:

    function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $quantity);
    }

    UniqueRandomNumbersWithinRange выдаст нам числа в заданном диапазоне, эти числа мы будем использовать что бы искать случайные строки в нашей таблице при помощи Doctrine, вот так:

    $em = $this->getDoctrine()->getManager();
    $repo = $em->getRepository('AppBundle:EntityName');
    $quantity = 5;
    $totalRowsTable = $repo->createQueryBuilder('a')->select('count(a.id)')->getQuery()->getSingleScalarResult();
    
    $randomIds = UniqueRandomNumbersWithinRange(1,$totalRowsTable,$quantity);
    
    $random_articles = $repo->createQueryBuilder('a')
    ->where('a.id IN (:ids)') // если у вас другое поле - поменяйте это
    ->setParameter('ids', $randomIds)
    ->setMaxResults(3)// Добавьте эту строку если вы хотите получить ограниченное количество записей (Если все IDs существуют вам будет нужно ограничение)
    ->getQuery()
    ->getResult();
    

    Эта статья является вольным переводом этой