Сегодня наконец-то нашел нормальное объяснение, почему
Подробнее с примерами: https://github.com/ShittySoft/symfony-live-berlin-2018-doctrine-tutorial/pull/3#issuecomment-460441229.
На радостях заменил в проекте все приведения на
Почирикал с @ocramius (https://twitter.com/vudaltsov/status/1201511202205163520). Он сказал, что приведение идентификаторов к примитивам через
В итоге пришлось вернуть
Выводы:
- Psalm & ImplicitToStringCast — 👍🔥,
-
- функциональные тесты — 😘🎉.
__toString лучше не использовать. Приводя объект к строке при помощи (string), мы можем забыть обработать null и получим на выходе '' вместо null. То есть еще один потенциальный способ выстрелить в ногу 🦵🔫.Подробнее с примерами: https://github.com/ShittySoft/symfony-live-berlin-2018-doctrine-tutorial/pull/3#issuecomment-460441229.
На радостях заменил в проекте все приведения на
$vo->toString(), убрал <ImplicitToStringCast errorLevel="suppress"/> в psalm.xml и удалил все методы __toString. Ну и конечно же функциональные тесты красные 🔴. Потому что Doctrine не умеет в ValueObject идентификаторы 😡. Конкретно на этой строке https://github.com/doctrine/orm/blob/2.7/lib/Doctrine/ORM/UnitOfWork.php#L1521 выполняется неявное приведение к строке 🤯.Почирикал с @ocramius (https://twitter.com/vudaltsov/status/1201511202205163520). Он сказал, что приведение идентификаторов к примитивам через
Type::convertToDatabaseValue хорошая идея, но может значительно сказаться на производительности.В итоге пришлось вернуть
__toString() {Entity}Id классам.Выводы:
- Psalm & ImplicitToStringCast — 👍🔥,
-
__toString — 👎 (но будьте внимательны в местах взаимодействия с инфраструктурой),- функциональные тесты — 😘🎉.
GitHub
Value types/value objects - use clearly defined types for anything that would otherwise be a scalar or composition of scalars by…
This patch introduces value objects into the mix.
What we did is isolating these concepts into these specific well-defined data structures, which would otherwise be strings, and therefore prone to ...
What we did is isolating these concepts into these specific well-defined data structures, which would otherwise be strings, and therefore prone to ...
Класс должен быть либо абстрактным, либо финальным.
Мотивация:
- https://www.tomasvotruba.cz/blog/2019/03/28/how-to-mock-final-classes-in-phpunit/;
- https://ocramius.github.io/blog/when-to-declare-classes-final/.
Кнуты и плётки:
- в PHP-CS-Fixer включаем
- для PHP CodeSniffer ставим нюхача https://github.com/matthewbdaly/abstract-or-final-sniff.
Как мокать:
- если над классом есть интерфейс, то мокать надо его, а не имплементацию;
- если это Entity или ValueObject, то лучше не мокать, а работать с полноценным экземпляром;
- в крайнем случае есть https://github.com/dg/bypass-finals. Как правильно его пристегнуть к PHPUnit: https://www.tomasvotruba.cz/blog/2019/03/28/how-to-mock-final-classes-in-phpunit/#4-single-hook.
Мотивация:
- https://www.tomasvotruba.cz/blog/2019/03/28/how-to-mock-final-classes-in-phpunit/;
- https://ocramius.github.io/blog/when-to-declare-classes-final/.
Кнуты и плётки:
- в PHP-CS-Fixer включаем
final фиксер;- для PHP CodeSniffer ставим нюхача https://github.com/matthewbdaly/abstract-or-final-sniff.
Как мокать:
- если над классом есть интерфейс, то мокать надо его, а не имплементацию;
- если это Entity или ValueObject, то лучше не мокать, а работать с полноценным экземпляром;
- в крайнем случае есть https://github.com/dg/bypass-finals. Как правильно его пристегнуть к PHPUnit: https://www.tomasvotruba.cz/blog/2019/03/28/how-to-mock-final-classes-in-phpunit/#4-single-hook.
ocramius.github.io
When to declare classes final
Declaring classes as final enhances our code quality and abstraction dramatically, but is it always correct?
❤1
Надеюсь, все знают, что начиная с Symfony 4.1 можно инлайнить конфигурацию роутов в путь.
Если вдруг нет, читайте новость от 22 марта прошлого года: https://symfony.com/blog/new-in-symfony-4-1-inlined-routing-configuration. Или ищите в документации https://symfony.com/doc/current/routing.html по слову
Но что если у нас UUID? Не указывать же каждый раз этот гигантский Regex!
Тут нам приходят на помощь параметры контейнера.
Подробнее тут: https://symfony.com/doc/4.2/routing/service_container_parameters.html (страница доступна только для 4.2, потому что документацию сейчас реструктуризируют).
То есть вместо
@Route("/studies/{studyId}", requirements={"studyId"="\d+"}, methods={"PUT"})
писать
@Route("/studies/{studyId<\d+>}", methods={"PUT"})
Если вдруг нет, читайте новость от 22 марта прошлого года: https://symfony.com/blog/new-in-symfony-4-1-inlined-routing-configuration. Или ищите в документации https://symfony.com/doc/current/routing.html по слову
inline.Но что если у нас UUID? Не указывать же каждый раз этот гигантский Regex!
@Route("/studies/{studyId<[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}>}", methods={"PUT"})Тут нам приходят на помощь параметры контейнера.
parameters:
regex.uuid: '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
@Route("/studies/{studyId<%regex.uuid%>}", methods={"PUT"})Подробнее тут: https://symfony.com/doc/4.2/routing/service_container_parameters.html (страница доступна только для 4.2, потому что документацию сейчас реструктуризируют).
Symfony
New in Symfony 4.1: Inlined routing configuration (Symfony Blog)
In Symfony 4.1 you can inline the requirements and default values in the route path to make the config more concise.
Записали на Пятиминутке PHP два подкаста.
https://5minphp.ru/episode72/ про
- прошедшую SymfonyCon Amsterdam и мой доклад,
- результаты Hack Day,
- Symfony Messenger,
- события предметной области,
- Symfony 5/6.
https://5minphp.ru/episode73/ про
- SymfonyCloud,
- более удобную разработку с Docker на маке,
- надежную отправку/доставку сообщений с RabbitMQ (https://vimeo.com/111998645),
- статический анализ кода при помощи Psalm и других инструментов.
Всех приглашаю послушать!
https://5minphp.ru/episode72/ про
- прошедшую SymfonyCon Amsterdam и мой доклад,
- результаты Hack Day,
- Symfony Messenger,
- события предметной области,
- Symfony 5/6.
https://5minphp.ru/episode73/ про
- SymfonyCloud,
- более удобную разработку с Docker на маке,
- надежную отправку/доставку сообщений с RabbitMQ (https://vimeo.com/111998645),
- статический анализ кода при помощи Psalm и других инструментов.
Всех приглашаю послушать!
Пятиминутка PHP
SymfonyCon 2019, Domain Events и новые компоненты Symfony 5
В этом выпуске Валентин Удальцов расскажет про SymfonyCon 2019, где он выступал как докладчик, а также активный участник Hack Day! Как прошел SymfonyCon 2019, организация и впечатления?Как принять …
Чтобы быстро и красиво оформлять консольные команды в привычном стиле Symfony, рекомендую использовать поставляемый с библиотекой
https://symfony.com/doc/current/console/style.html
Symfony\Component\Console\Style\SymfonyStyle. У него куча хелперов почти на все случаи жизни.https://symfony.com/doc/current/console/style.html
Постоянно работаю с UUID, поэтому повесил https://plugins.jetbrains.com/plugin/8320-uuid-generator/ на
Ctrl+U.JetBrains Marketplace
UUID Generator - IntelliJ IDEs Plugin | Marketplace
UUID, ULID and CUID generator plugin for IntelliJ based IDEs.. For example : 123e4567-e89b-12d3-a456-426655440000. You will find it in the Generate popup -> Random...
Обновляем
Она покажет все доступные рецепты и возможные обновления.
https://github.com/symfony/flex/pull/562
#Symfony #Flex
symfony/flex до 1.6.0 и запускаем команду composer recipes!Она покажет все доступные рецепты и возможные обновления.
https://github.com/symfony/flex/pull/562
#Symfony #Flex
Суперподробный чит-шит по Symfony Messenger.
https://twitter.com/andreiabohner/status/1206422366143885312
#Symfony #Messenger
https://twitter.com/andreiabohner/status/1206422366143885312
#Symfony #Messenger
Twitter
Andréia Bohner
Symfony 4.4 Messenger Cheat Sheet https://t.co/LW7Sp5GNL7
Отчаянно рекомендую свежий доклад @ocramius про тестирование и обеспечение качества кода.
https://www.youtube.com/watch?v=8rdTSYljts4
Из него вы узнаете:
- про график "этап разработки / цена ошибки" (https://youtu.be/8rdTSYljts4?t=340),
- почему отдел QA не нужен (https://youtu.be/8rdTSYljts4?t=526),
- про архитектуру и Architecture Decision Record (https://youtu.be/8rdTSYljts4?t=990),
- почему важна типизация (https://youtu.be/8rdTSYljts4?t=1771),
- про Psalm (https://youtu.be/8rdTSYljts4?t=1844),
- о "Пирамиде Маслоу" проекта (https://youtu.be/8rdTSYljts4?t=3357),
- про инструменты тестирования и анализа кода.
Наверняка что-то забыл или не отметил, лучше смотрите целиком.
#PHP #Testing #QA
https://www.youtube.com/watch?v=8rdTSYljts4
Из него вы узнаете:
- про график "этап разработки / цена ошибки" (https://youtu.be/8rdTSYljts4?t=340),
- почему отдел QA не нужен (https://youtu.be/8rdTSYljts4?t=526),
- про архитектуру и Architecture Decision Record (https://youtu.be/8rdTSYljts4?t=990),
- почему важна типизация (https://youtu.be/8rdTSYljts4?t=1771),
- про Psalm (https://youtu.be/8rdTSYljts4?t=1844),
- о "Пирамиде Маслоу" проекта (https://youtu.be/8rdTSYljts4?t=3357),
- про инструменты тестирования и анализа кода.
Наверняка что-то забыл или не отметил, лучше смотрите целиком.
#PHP #Testing #QA
YouTube
Aggressive PHP Quality Assurance in 2019 | Marco Pivetta
PHP has a reputation for being a very flexible, yet very messy programming language: Keeping the chaos at bay requires a non-trivial amount of cognitive load and technical expertise.
In this talk, we will explore how quality assurance for popular open source…
In this talk, we will explore how quality assurance for popular open source…
И в продолжение темы тестирования. Доклад про то, почему интеграционные тесты — жульничество. Почему их количество всегда растет, а качество проекта при этом падает. Как правильно писать изолированные (юнит-) тесты и как тестировать контракты.
Намеренно не расписываю тайм-коды, потому что этот доклад представляет собой цельное повествование от проблемы до решения.
https://vimeo.com/80533536 или https://www.youtube.com/watch?v=VDfX44fZoMc
#Testing #TDD
Намеренно не расписываю тайм-коды, потому что этот доклад представляет собой цельное повествование от проблемы до решения.
https://vimeo.com/80533536 или https://www.youtube.com/watch?v=VDfX44fZoMc
#Testing #TDD
Vimeo
J.B. Rainsberger - Integrated Tests Are A Scam
Integrated tests are a scam. You’re probably writing 2-5% of the integrated tests you need to test thoroughly. You’re probably duplicating unit tests…
В недавно вышедшей Symfony 5.0 появилась компонента String.
Актуальный обзор в сегодняшней новости: https://symfony.com/blog/new-in-symfony-5-0-string-component.
Документация: https://symfony.com/doc/current/components/string.html.
Документация по использованию в Twig: https://twig.symfony.com/doc/2.x/filters/u.html.
Наглядная презентация идеи от автора библиотеки Николаса: https://speakerdeck.com/nicolasgrekas/symfony-string-flexible-handling-of-unicode.
#PHP #Symfony
Актуальный обзор в сегодняшней новости: https://symfony.com/blog/new-in-symfony-5-0-string-component.
Документация: https://symfony.com/doc/current/components/string.html.
Документация по использованию в Twig: https://twig.symfony.com/doc/2.x/filters/u.html.
Наглядная презентация идеи от автора библиотеки Николаса: https://speakerdeck.com/nicolasgrekas/symfony-string-flexible-handling-of-unicode.
#PHP #Symfony
Symfony
New in Symfony 5.0: String Component (Symfony Blog)
Symfony 5.0 introduces a new String component which deals with bytes, UTF-8 code points and grapheme clusters in a unified way, provides an object-oriented API for strings, and includes a slugger.
Помог обновить https://github.com/dunglas/doctrine-json-odm для совместимости с Symfony 5. Кто юзает этот замечательный пакет, апайте до 1.0.1.
Как правило, такие PR тривиальны и занимают до получаса времени. Позитивный сценарий:
• форкаем и клонируем репозиторий;
• добавляем в
•
• запускаем локально тесты либо сразу создаем PR и ждем результатов CI;
• попутно могут возникнуть какие-то мелочи, смотрите мой https://github.com/dunglas/doctrine-json-odm/pull/83.
Призываю вас участвовать в обновлении используемых вами пакетов. Это элементарный способ законтрибьютить, поближе познакомитьсся с кодом и авторами да и просто получить 🟩 в карму на GitHub.
#OSS #Contributing #Symfony
Как правило, такие PR тривиальны и занимают до получаса времени. Позитивный сценарий:
• форкаем и клонируем репозиторий;
• добавляем в
composer.json к пакетам symfony/* версии || ^5.0 ;•
composer update;• запускаем локально тесты либо сразу создаем PR и ждем результатов CI;
• попутно могут возникнуть какие-то мелочи, смотрите мой https://github.com/dunglas/doctrine-json-odm/pull/83.
Призываю вас участвовать в обновлении используемых вами пакетов. Это элементарный способ законтрибьютить, поближе познакомитьсся с кодом и авторами да и просто получить 🟩 в карму на GitHub.
#OSS #Contributing #Symfony
GitHub
GitHub - dunglas/doctrine-json-odm: An object document mapper for Doctrine ORM using JSON types of modern RDBMS.
An object document mapper for Doctrine ORM using JSON types of modern RDBMS. - dunglas/doctrine-json-odm
Мета-вопросы а-ля "Можно спросить?" или "Ребят, есть вопрос по %technology%" усложняют общение в онлайне. Спрашивайте сразу по делу. Это не про вежливость — это про уважение к чужому времени. Нет глупых вопросов, есть бесполезные предисловия.
https://nometa.xyz/
https://nometa.xyz/
Крутая статья про контринтуитивный парсинг JSON. Ценность её не только в исследовании причины невалидности выражения
Я был бы счастлив прочитать такую статью несколько лет назад, перед тем как написать свой первый кастомный тег для Twig и DQL функцию для Doctrine ORM.
https://nullprogram.com/blog/2019/12/28/
[01], но и в ёмком экскурсе в парсеры на примере формата, который знают все.Я был бы счастлив прочитать такую статью несколько лет назад, перед тем как написать свой первый кастомный тег для Twig и DQL функцию для Doctrine ORM.
https://nullprogram.com/blog/2019/12/28/
Внезапно узнал, что можно передавать массив искомых значений в аргументе
Пример:
В документации можно найти на странице https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-objects.html#by-simple-conditions по фразе If you pass an array of values.
Надеюсь, в отличие от меня вы и так это знали и не создавали почем зря query builder.
$criteria метода EntityRepository::findBy(). Он автоматически будет преобразован в выражение IN(...).Пример:
$em->getRepository(Question::class)->findBy([
'id' => [
'82f06c7f-7513-464d-972d-857fb169f86a',
'25ee6a8d-72b8-449f-9409-cdb545b28f5b',
],
]);
В документации можно найти на странице https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-objects.html#by-simple-conditions по фразе If you pass an array of values.
Надеюсь, в отличие от меня вы и так это знали и не создавали почем зря query builder.