• Когда лучше использовать примеси, а когда общие классы?

    @Flying
    Общие CSS классы можно использовать если вы контролируете установку этих CSS классов, ведь это делается в HTML. Естественно в этом случае объём результирующего CSS кода будет меньше, но в сложных случаях логика расстановки CSS классов может быть не самой тривиальное.

    В отличие от них mixin'ы влияют на генерируемый CSS. Кода в итоге скорее всего будет больше, но он будет более изолированным и менее будет зависеть от управления HTML. В плане производительности, если подходить с умом и не строить многоуровневые сложные селекторы без надобности - особых проблем быть не должно.

    Также не стоит забывать о ещё одном способе горизонтального расширения - placeholder'ах. Их использование позволяет сэкономить на объёме CSS кода за счёт исключения дублирования, но может иметь не самые очевидные последствия без понимания того что именно стоит за этой абстракцией.
    Ответ написан
    1 комментарий
  • Почему Webpack Encore грузит только имя файла, а не его содержимое (require().default)?

    @Flying
    Если вы в Webpack используете какой-то специальный loader - то почему вы рассчитываете что Webpack Encore как-то магически тоже будет его использовать?

    Простая проверка списка зависимостей покажет вам что raw-loader в список зависимостей не входит, а значит с точки зрения Webpack Encore, как и с точки зрения Webpack (где он есть только в dev.dependency) он является custom loader'ом что явно должно было привести вас к соответствующему разделу документации.
    Ответ написан
  • Как сделать уникальным массив массив ассоциированных массивов?

    @Flying
    Например вот так:
    count($array) === count(array_unique(array_column($array, 'NUMBER')));
    Ответ написан
    1 комментарий
  • Как задействовать CSS в зависимости от значения scrollTop (pageYOffset)?

    @Flying
    Подобная функциональность - идеальный кейс для использования IntersectionObserver. Добавляете observer на элементы, соответствующие вашим экранам, определяете пороговое значение срабатывания - и дальше просто реагируете на события переходов между состояниями.

    Конечно возможны нюансы с тем что, к примеру, несколько (больше двух) ваших страниц попадут во viewport (помним что мониторы можно развернуть и вертикально, получив высоту viewport'а в 2k пикселей), но в целом получается весьма стабильно работающая схема.

    Дополнительный плюс в том что вам не нужно заниматься отслеживанием события scroll т.к. это и сложнее в реализации и менее надёжно и есть связанные с ним проблемы (подробнее в документации)
    Ответ написан
  • Как понять какой именно шрифт отображается?

    @Flying
    Не скажу за Chrome, в Firefox это видно на вкладке Fonts:
    5fb038e1e16b2507425378.png
    Ответ написан
    Комментировать
  • Как получить getUser из JWT в контроллере Symfony?

    @Flying
    Метод getUser() есть в AbstractController, так что вы можете просто вызывать его если ваши контроллеры наследуются от AbstractController.

    Альтернативно вы можете получать пользователя через аргумент action метода благодаря UserValueResolver

    Дешифровать в контроллерах вам точно ничего не нужно, почитайте как работает система Security в Symfony. User, после его получения в результате процесса аутентификации, хранится в security токене в том виде в котором вы его туда отдали, в вашем случае - в виде entity.
    Ответ написан
  • Репозиторий с примером RESTful API на NodeJS?

    @Flying
    Например в RealWorld можно выбрать реализации backend / frontend на любой вкус, в том числе и на NodeJS
    Ответ написан
    1 комментарий
  • Как правильно проиндексировать большой объем информации в elasticsearch?

    @Flying
    Используйте Bulk API, через него загрузка в десятки раз быстрее чем по одному документу заливать.

    Правда закидывать всё одним bulk'ом тоже не стоит, практика показывает что пакеты порядка сотни документов за раз - вполне, хотя от размеров одного документа тоже зависит.
    Ответ написан
    Комментировать
  • Как правильно работать с сторонним api?

    @Flying
    Конечно контроллер - не место для подобных действий.

    Как правильно указал Владимир Коротенко - перенос кода, отвечающего за работу с внешним API в отдельный сервис - это первое что вам нужно сделать. Это действие открывает для вас массу возможностей: подмена сервиса для разных сценариев, использование заглушек для тестов, вызовы вне контроллеров и т.д. Кроме того сам код при этом становится более простым и поддерживаемым, а также лучше соответствует принципам SOLID.

    Если после выделения сервиса вы поймёте что для вас необходима возможность изменения его реализации - важно выделить ключевые методы в интерфейс и использовать именно интерфейс для внедрения зависимостей в те же контроллеры.

    Для реализации самих запросов внутри сервиса логично использовать Symfony HTTP Client.

    После этого у вас возможны различные сценарии в зависимости от того что же этот API делает.

    Если вы забираете из API данные для подготовки своего ответа и эти данные меняются часто и должны быть всегда актуальны (к примеру какое-нибудь значение котировки акции или курса валюты) - вы вызываете ваш сервис напрямую, а он делает запрос и возвращает ответ.

    Если вы забираете из API данные для подготовки своего ответа, но сами эти данные меняются не постоянно - логично будет добавить в ваш сервис поддержку кэширования с использованием Symfony Cache.

    Если вы забираете данные из API или отправляете данные туда, но они не зависят от контекста текущего запроса - этот процесс логичнее всего вынести в консольную команду, реализованную через Symfony Console и дёргать её по cron'у.

    Альтернативно, если вы используете Symfony 4.4 или 5.x - вы можете организовать этот процесс через новый Symfony Messenger. Он же будет лучшим вариантом если, к примеру, запросов много или они тяжёлые и вам нужно организовать их распределение.
    Ответ написан
    Комментировать
  • Можно ли как-нибудь проверить свои знания laravel, symfony или любой другой технологии?

    @Flying
    По Symfony можно попробовать сдать сертификационный экзамен, правда это не сказать чтобы дёшево.
    Ответ написан
    Комментировать
  • Попинайте 2. Удалось ли исправить устаревший код, который забраковал работодатель?

    @Flying
    Согласен с FanatPHP по поводу того что изменения, по сравнению с предыдущим вариантом, просто колоссальные, поздравляю!

    Однако сразу видны те направления движения которые стоит рассматривать в первую очередь:

    1. Вам стоит лучше изучить возможности языка. PHP развивается очень динамично и в 7-й версии было добавлено огромное количество вкусных возможностей, про них стоит знать и ими стоит пользоваться
    2. Необходимо лучше изучить имеющуюся на данный момент экосистему готовых пакетов, это позволит вам использовать готовые, проверенные решения вместо изобретения своих велосипедов. Подключение Twig - первый шаг, но далеко не последний
    3. Вам обязательно стоит посвятить время изучению кода популярных проектов. Это многое может рассказать вам о подходах к решениям, паттернах и т.п. Конечно, параллельно нужно будет выяснять значения массы используемых терминов чтобы лучше понимать происходящее, это тоже пойдёт вам на пользу.
    4. Смотрите как развиваются другие технологии, которые вы используете, таблицами сейчас не верстают :)
    5. Рекомендую рассмотреть вариант использования для написания кода нормальной IDE, к примеру PHPStorm, это существенно улучшит вашу производительность и убережёт от массы ошибок


    Теперь более предметно:

    Оформление кода:

    Вы утверждаете что код соответствует PSR-2 (кстати, актуальный - PSR-12), однако есть мелкие огрехи (раздел 2.2).

    Оформление composer.json:

    Лучше указывать требования к платформе, в вашем случае - как минимум версию PHP т.к. platform requirements проверяются Composer'ом при установке.

    Поскольку ваш проект - не библиотека, то composer.lock тоже должен быть частью репозитория.

    Про настройки autoload'а вам уже сказали, обращу только внимание на то что сейчас структура репозитория отражает PSR-0, а не актуальный PSR-4, при использовании PSR-4 ваш код проекта лежал бы в src.

    Организация репозитория

    Код проекта должен лежать за пределами web root, поэтому вам явно не хватает папки public с единственным index.php

    Конфигурация

    Конфигурирование через константы - весьма устаревший подход. К примеру представьте что вы разворачиваете этот код на production сервере и вам нужно сменить данные для подключения к базе данных не создавая локальных изменений в рабочей копии. Сейчас у вас это не получится. Выход: читаем про
    12 factor app и, в частности, раздел config, а затем подключаем в проект, к примеру, vlucas/phpdotenv или symfony/dotenv

    Сервисы

    Использование bootstrap.php - хорошо, но для организации работы с сервисами сейчас как правило используются dependency injection контейнеры, даже PSR-11 для них есть. В текущем виде ваш подход слабо расширяем, а передача сервисов через глобальные переменные - так себе идея по многим причинам.

    Понятно что вворачивать DI container для примера на три файлика - overkill, но с самим подходом вам следует ознакомиться. Из реализаций самая популярная сейчас - symfony/dependency-injection, но есть и альтернативы.

    Автолоадер

    Про autoload.php вам уже сказали, вместо него стоит корректно конфигурировать автозагрузку в composer.json и полагаться на то что Composer вам сгенерирует. Он ведь умеет всё это и оптимизировать при необходимости.

    Внешние пакеты

    Для новых проектов рекомендуется выбирать актуальные и поддерживаемые версии пакетов. Хотя Twig 1.x ещё поддерживается, тем не менее актуальная версия - 3.x.

    Обработка ошибок

    Попробовать сделать это самостоятельно, безусловно, полезно чтобы лучше разобраться как это работает, но для реальной работы лучше полагаться на проверенные решения, к примеру filp/whoops или symfony/error-handler

    Типы данных

    Важно помнить что PHP с версии 7.0 поддерживает указание скалярных типов для аргументов и
    возвращаемых значений, с 7.1 - nullable типы и class constant visibility, а с 7.4 - типизированные свойства. Всё это гораздо надёжнее чем описание типов через аннотации и этим стоит пользоваться.

    Также повсеместно в коде используется нестрогое сравнение, тогда как очень желательно всегда использовать строгое (документация).

    Data Objects

    Сейчас Place и PlaceFilter по сути являются data объектами т.е. они не содержат самостоятельной логики, а просто переносят некие данные. При этом оба этих класса имеют пустые конструкторы (которые, кстати, лучше убирать), а загрузка данных организована через setter методы. Это позволяет изменить данные в них в произвольные моменты времени что вряд ли является желаемым поведением. Вместо этого подобные объекты лучше организовывать в виде immutable объектов (статья с примерами) чтобы не позволять ненужного нарушения целостности данных. Альтернативно, к примеру, для PlaceFilter может лучше подходить использование паттерна
    Builder
    , хотя в википедии не самый лучший пример.

    Именование

    Все мы, надеюсь, помним про две сложные проблемы, здесь как раз проявляется вторая из них. PlaceFactory ну никак не является реализацией одноимённого паттерна.

    Оптимизации

    Понятно что это мелочи, но явно видно что компиляцию запросов (1, 2) можно кэшировать вместо того чтобы перекомпилировать каждый раз.

    References

    PDOStatement::bindParam() принимает аргумент $variable как reference, а в коде в этот аргумент передаётся выражение что недопустимо.

    Английский язык

    Я специально почти везде по тексту давал ссылки на информацию на английском языке т.к. он - основной язык в нашей индустрии и его важно знать и использовать.
    Ответ написан
    3 комментария
  • Хочу начать заниматься веб дизайном (фотошоп, фигма) и не могу определиться с ноутбуком. Какой выбрать?

    @Flying
    Возьмите лучше б/у, но более развитый ноутбук, а не что-то из магазина чтобы не переплачивать за новую вещь. Тем более что в магазинах зачастую ширпотреб, а что-то реально нужное как правило под заказ.

    Для реальной работы вам важно будет обращать внимание в первую очередь на монитор. Это, обязательно, IPS матрица, цветовой охват (100% sRGB или AdobeRGB - это конечно хорошо, но именно для веб-дизайна - не слишком принципиально) хорошая контрастность, достаточное разрешение (FullHD или выше). По диагонали вы упрётесь максимум в 17", а скорее даже в 15". Очень важно - калибровка цвета. Лучше ищите мастера со спектрофотометром, если нет - смотрите на "домашние" калибраторы типа SpyderX.

    Если планируете работать с Photoshop'ом и относительно большими макетами - то памяти нужно столько сколько можно запихать (32 если получится, или больше) + быстрый SSD (лучше NVMe, хотя не принципиально) т.к. Photoshop память очень любит. Figma менее требовательная, но больше памяти ещё никогда не вредило :)

    Видеокарта лучше дискретная т.к. у неё отдельная память, но важным это становится только для довольно больших макетов в Photoshop'е.

    Для того чтобы с влезть в бюджет в такой ситуации - оптимально смотреть на варианты б/у ноутбуков у которых есть свободные слоты под память и есть возможность замены диска. Если брать такую модель в минимальной конфигурации - потом её можно будет растянуть самостоятельно, добавляя память и заменяя / добавляя диски.
    Ответ написан
    Комментировать
  • Как реально получить MIT лицензию?

    @Flying
    Если речь идёт о лицензировании вашего кода под лицензией MIT - то достаточно просто указать это в readme либо приложить файл лицензии с текстом, взятым отсюда.
    Ответ написан
    Комментировать
  • Отличие создание объекта через new и dependency injection?

    @Flying
    При создании экземпляра объёкта через new вы просто создаёте экземпляр объекта т.к. это конструкция самого языка. Если этот объект нужно создавать как-то специфически, к примеру если надо передавать что-то в конструктор или как-то дополнительно конфигурировать и т.п. - всё это ваша ответственность. Если вам понадобится этот же объект где-то в другом месте проекта - то передача его туда - тоже ваша ответственность.

    Dependency injection container, в отличие от этого обеспечивает следующие задачи:
    1. Централизованное хранилище объектов и интерфейс для их получения
    2. Автоматическое корректное создание сконфигурированных экземпляров объектов

    Конкретные реализации могут предоставлять дополнительные сервисы, но описанные выше - основные. Конечно, внутри там в конечном итоге тот же new, просто логика создания, конфигурирования и хранения объектов вынесена в отдельную стандартизированную сущность которой можно и нужно пользоваться для упрощения и улучшения качества своего кода.
    Ответ написан
    3 комментария
  • Ноутбук для программирования 2020?

    @Flying
    Я бы брал максимально возможный CPU (т.к. он обычно не обновляется) и смотрел на возможность расширения памяти и диска. Т.е. 8Gb на борту и слоты под 32Gb лучше чем 16Gb без возможности расширения. В этом случае вы оставляете себе возможность при необходимости в дальнейшем докупить и поставить больше памяти без необходимости менять весь ноут, что явно обойдётся дешевле.

    То же самое и с диском - если его можно менять и / или есть слоты под дополнительные диски - то вы сможете поменять конфигурацию и / или расширить диск когда будет нужно, не упираясь в необходимость взять всё и сразу.

    Стоит сразу учесть размер монитора. Конечно все люди разные, но программировать на 13" без внешнего экрана - так себе удовольствие как по мне, поэтому 15" явно лучше. HiDPI экраны (4K и Retina) явно дороже чем FullHD, а их необходимость именно для программирования на Python - сомнительна, так что вполне можно сэкономить и взять просто FullHD. Меньше FullHD точно не стоит, информации на экран выводить нужно немало.

    В целом в ваш бюджет вполне влезает, к примеру, Lenovo T590 (а то и новый T15 Gen 1), особенно если брать с 8Gb на борту. К нему отдельно можно купить планку памяти на 32Gb и получить 40Gb. SSD тоже меняется не особо дорого если потребуется. В итоге получите машинку с современным процессором, кучей памяти (а 16Gb может легко начать не хватать) и заточенную именно под работу. Как минимум клавиатура у Lenovo точно хорошая :)
    Ответ написан
    Комментировать
  • Какой тип лабиринтов выбрать и какой алгоритм использовать?

    @Flying
    На хабре есть шикарная статья по этой теме, думаю что в качестве отправной точки имеет смысл начать с неё
    Ответ написан
    Комментировать
  • Как победить Undefined index в UnitOfWork при сохранении внутри postRemove?

    @Flying
    В документации к событию postRemove прямо указано что это событие вызывается внутри метода flush(). Таким образом вызывая $this->entityManager->flush() внутри postRemove вы, фактически порождаете потенциально бесконечный цикл, поэтому "Undefined index" на самом деле - наименьшая из ваших проблем :)

    Более корректно будет организовать работу примерно следующим образом:
    1. Вынести логику сохранения изменений в отдельный сервис
    2. Обернуть процесс сохранения изменений в транзакцию
    3. В lifecycle методах не пытаться писать данные сразу, а вместо этого собирать информацию для записи в некую коллекцию, в простейшем случае - массив
    4. После основного flush'а проверять содержимое коллекции и если там что-то есть - формировать отдельный набор изменений в entities и делать новый flush.
    5. Если всё прошло хорошо - в конце делать commit транзакции
    Ответ написан
    7 комментариев
  • Как научить PhpStorm понимать __callStatic?

    @Flying
    Вам необходимо описать маппинги между аргументами и типами результатов в формате PHPStorm Advanced Metadata.
    Ответ написан
    Комментировать
  • Зачем нужен fosrestbundle в symfony?

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

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

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

    @Flying
    Б/у ThinkPad вполне влезет в этот бюджет, смотри W серию с FullHD экраном т.к. там IPS.

    На том же Avito есть и W550 на i7 по цене порядка 50к и более старые W530 / W540 по цене в 30-40к. Потом добавляешь туда SSD (есть m.2 разъём) и памяти сколько нужно (32Gb тянет даже W530) и получаешь хорошую рабочую машинку с отличной клавиатурой и почти неубиваемую.

    Супруге собрал W530 с 32Gb и тремя дисками (ей с графикой работать), всё прекрасно работает уже не первый год, а ноут обошёлся в своё время в 450$
    Ответ написан
    2 комментария