• Doctrine does not have a property named "mappedBy"?

    @Flying
    Всё очень просто: В коде Product в строке 123 вы используете
    @ORM\ManyToOne(targetEntity="Category", mappedBy="product")

    тогда как для ManyToOne необходимо использовать inversedBy, это прямо описано в документации и видно в коде этой аннотации.
    Ответ написан
    Комментировать
  • Как среди постов найти минимальную дату, которая создается через дополнительное поле ACF?

    @Flying
    Это описано в официальной документации ACF, вам просто нужно написать правильно запрос:
    $posts = get_posts([
      'post_type'  => 'tc_events',
      'numposts'   => 1,
      'meta_key'   => 'event_date_new',
      'orderby'    => 'meta_value',
      'order'      => 'ASC'
    ]);
    $post = array_shift($posts);
    Ответ написан
  • Имеет ли смысл начать изучение Symfony если более-менее знаком с Laravel?

    @Flying
    Вам стоит начать воспринимать ваше отношение к документации Laravel и Symfony как индикатор того что вам есть ещё что изучать и в чём разбираться. Это нормальное развитие разработчика.

    Честно говоря пока что ваши реплики не очень хорошо связуются между собой. "В общих чертах знаком", "не понимаю всего этого ООП", но при этом "могу написать на Laravel магазин какой" - это для меня звучит очень странно. Я работаю с Symfony уже порядка 5 лет, но никак не могу сказать что влёгкую напишу на ней магазин. Вот здесь команда Sylius магазин на Symfony пишет аж с 2012-го года, до релиза 1.0 добрались через 5 лет, для меня это хороший показатель. Вы точно уверены в отсутствии у вас эффекта Даннинга-Крюгера?

    Уверен, что познакомившись с ООП не только с практической, но и с теоретической стороны (возьмите хоть ту же Википедию для начала и далее по ссылкам, заодно и про другие парадигмы узнаете) вы начнёте лучше понимать и зачем оно нужно, какие проблемы и как призвано решить и т.д.

    Вполне вероятно что вы просто пытаетесь следовать довольно популярному сейчас подходу взятия новых подходов в программировании штурмом (т.к. судя по ответом на том же тостере - в целом вы занимаетесь программированием довольно давно). Это работает до определённого предела, но важно понимать что на любом пути существуют разные этапы и переход между этапами пути - отдельная большая работа. Понимание различных подходов к решению задач (и ООП подход как один из них) на уровне самих механизмов, стоящих за ними идей, а не на уровне синтаксиса - важный этап, но зачастую непростой т.к. требует внесения существенных изменений в модель вашего восприятия. Тем не менее, пройдя его, вы будете ясно видеть и "зачем гейты и политики" и т.п.

    Ответ получился чуть в сторону, так что back to topic: знакомиться с Symfony однозначно стоит, но не в качестве спасения от непонятной документации Laravel (там, как правильно написал DevMan её ещё меньше и она ещё сложнее), а для изучения того как на PHP можно писать действительно качественный, стабильный и поддерживаемый код. Фактически знакомиться с Symfony лучше даже не столько через чтение документации, а через изучение её исходников с отладчиком. Несколько недель подобных путешествий (с параллельным поиском ответов на вопросы "что тут вообще происходит?!") дадут вам очень много в плане развития, рекомендую :)
    Ответ написан
  • Как скорректировать отображение событий в Firefox инспекторе DOM?

    @Flying
    Эта конструкция специфична для jQuery и по сути означает что реальный обработчик вешается на body, но в нём есть дополнительная проверка Event.target на совпадение с указанным селектором.

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

    @Flying
    В SCSS это легко решается через @extends:
    %subsclasses-color {
      .sub1, .sub2, .sub3 {
        color:red;
      }
    }
    .main1 {
      @extends %subclasses-color;
    }
    .another-main {
      @extends %subclasses-color;
    }
    Ответ написан
  • Какие принципы SOLID здесь нарушены?

    @Flying
    С моей точки зрения здесь в первую очередь нарушается S (принцип единственной ответственности). Box в целом не должен уметь что-то кроме хранения фигур. Как правильно заметил vgbege - из задачи не следует что в дальнейшем вариантов подсчёта каких-то метрик по фигурам с Box'е не станет больше, так что в первую очередь я бы выносил отдельно калькулятор. Также у вас нет обобщающего интерфейса для IArea и IShape из-за чего и возникает путаница в addShape.

    В целом у меня получилось нечто подобное:
    /**
     * Основной интерфейс для всех фигур которые можно хранить в Box'е
     */
    interface IFigure
    {
    
    }
    
    /**
     * Интерфейс для фигур которые могут обладать площадью
     */
    interface IArea extends IFigure
    {
        public function getArea(): float;
    }
    
    /**
     * Интерфейс для фигур которые могут обладать цветом заливки
     */
    interface IFillColor
    {
        public function setFillColor(string $color): self;
    
        public function getFillColor(): string;
    }
    
    /**
     * Обобщённый интерфейс для фигур, обладающих и цветом и площадью
     * По факту, думаю, он не имеет смысла, но нужен по условию задачи
     */
    interface IShape extends IArea, IFillColor
    {
    
    }
    
    /**
     * Коробка для хранения фигур
     */
    class Box
    {
        /**
         * @var IFigure[]
         */
        private $figures = [];
    
        /**
         * @param IFigure[] $figures
         */
        public function __construct(array $figures = [])
        {
            // Добавляем полученные через конструктор фигуры в объект
            // Используем addFigure() чтобы проконтролировать корректность типов
            array_walk($figures, [$this, 'addFigure']);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function addFigure(IFigure $figure): self
        {
            $this->figures[] = $figure;
            return $this;
        }
    
        /**
         * @param IFigure $figure
         * @return bool
         */
        public function hasFigure(IFigure $figure): bool
        {
            return in_array($figure, $this->figures, true);
        }
    
        /**
         * @param IFigure $figure
         * @return $this
         */
        public function removeFigure(IFigure $figure): self
        {
            $this->figures = array_filter($this->figures, static function (IFigure $f) use ($figure) {
                return $f !== $figure;
            });
            return $this;
        }
    
        /**
         * @return IFigure[]
         */
        public function getFigures(): array
        {
            return $this->figures;
        }
    }
    
    /**
     * Интерфейс для калькуляторов фигур в Box'ах
     */
    interface IFigureCalculator
    {
        /**
         * @param Box $box
         * @param mixed ...$args
         * @return mixed
         */
        public function calculate(Box $box, ...$args);
    }
    
    /**
     * Пример калькулятора
     */
    class AreaCalculator implements IFigureCalculator
    {
        public function calculate(Box $box, ...$args): float
        {
            // Получаем список фигур которые обладают площадью
            $figures = array_filter($box->getFigures(), static function (IFigure $figure) {
                return $figure instanceof IArea;
            });
            // Получаем цвет из дополнительных аргументов калькулятора
            $color = array_shift($args);
            if ($color) {
                // У нас задан цвет, фильтруем фигуры по цвету
                $figures = array_filter($figures, static function (IFigure $figure) use ($color) {
                    return $figure instanceof IFillColor && $figure->getFillColor() === $color;
                });
            }
            // Подсчитываем суммарную площадь
            return array_reduce($figures, static function (float $area, IArea $figure) {
                return $area + $figure->getArea();
            }, 0);
        }
    }


    В качестве альтернативы я рассматривал также вариант дать Box'у возможность самому считать метрики через создание у него метода:
    public function calculate(IFigureCalculator $calculator, ...$args)

    но потом решил что лучше не захламлять интерфейс чтобы не усложнять логику.
    Ответ написан
    7 комментариев
  • Есть ли бандл для Symfony на подобие DoctrineAuditBundle, но с возможностью формирования более расширенного человекочитаемого текста изменений?

    @Flying
    Это довольно просто делается через Doctrine lifecycle events. Вешаете обработчики на preUpdate, pretPersist, prePremove, собираете из переданных вам событий информацию для формирования нужного вам лога, затем в postFlush из собранной информации формируете запись в лог и записываете.
    Ответ написан
    Комментировать
  • Как переопределить параметр mixin, не трогая исходники?

    @Flying
    Вы можете передавать её как именованный аргумент при вызове, т.е.
    @include button-variant($active-background: white, $active-border: lightgrey);
    Ответ написан
    Комментировать
  • Как корректно сверстать подобное?

    @Flying
    У общего блока добавляем:
    background-image: url(<картинка с точками, можно как data url>);
    background-position: top left; 
    background-repeat: repeat-y; 
    padding-left: <размер фона по Y + отступ до контента>;

    Для каждого из элементов добавляем:
    position: relative; 
    &:before {
      content: '';
      position: absolute;
      top: 0;
      left: 0 - <размер отступа>;
      transform: translate(50%, 50%);
      border: <размер белого пространства сверху / снизу> solid #fff;
      <и здесь либо рисуем элемент через width, height, background-color, border-radius либо картинками, думаю что второе предпочтительнее> 
    }

    Правда такой способ в зависимости от высоты элементов может дать частично закрытые точки, для того чтобы этого избежать надо будет контролировать высоту элементов с тем чтобы она была кратна шагу между точками.
    Ответ написан
    Комментировать
  • Как на php ставить задачи в очередь например при парсинге сайта?

    @Flying
    Подобная задача решается через т.н. брокеры сообщений (Message broker). Есть несколько возможных вариантов, к примеру выделенные сервера, реализующие протокол AMQP (например RabbitMQ, ActiveMQ и другие), стриминговые сервера (к примеру Kafka), сервисы очередей (Amazon SQS и подобные), а также другие реализации паттерна PubSub, к примеру в Redis.

    Идея состоит в том что вы создаёте очередь (или более сложную структуру, здесь в разных реализациях по-разному) в которую с одной стороны публикуются сообщения, а с другой стороны вызываются обработчики, подписанные на те или иные сообщения в очереди.

    В вашем сценарии скорее всего будет подразумеваться две очереди:
    1. Очередь задач на scraping. а которую подписываются множество worker'ов, осуществляющих непосредственный сбор данных
    2. Очередь с результатами сбора данных, куда worker'ы будут скидывать данные и на которую подписываются обработчики, решающие что же делать с данными дальше

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

    Для PHP существуют немало binding'ов к серверам, реализующим message brokering. Не знаю что именно на сервер вы выберете, поэтому навскидку приведу php-amqplib/php-amqplib для работы с AMQP (в первую очередь с RabbitMQ), enqueue/amqp-tools (также для AMQP) и superbalist/php-pubsub для реализации PubSub паттерна, к примеру через Redis.

    Вы не указали на чём написан ваш проект, но в целом также можно посмотреть в сторону компонента Messenger для Symfony, его можно использовать и вне Symfony и он даёт хорошую базу для реализации схем обмена сообщениями.
    Ответ написан
    3 комментария
  • Gulp 4 выдает в «The following tasks did not complete... Did you forget to signal async completion». Как это исправить?

    @Flying
    У вас вызов cb() стоит после return т.е. он вообще не вызывается. Но поскольку в списке аргументов он есть - gulp ожидает его вызова и, не дождавшись, ругается.

    В вашем случае cb вообще не нужен, просто уберите его из списка аргументов и всё начнёт работать.
    Ответ написан
  • Как правильно реализовать теги в Symfony?

    @Flying
    п.п.3 и 4 реализуются довольно просто через lifecycle events в Doctrine. Просто на preRemove вешаете обработчик, в нём проверяете тип entity и, если это что-то подходящее (статья или тег) то проверяете связи удаляемой entity и по необходимости подчищаете.
    Ответ написан
    5 комментариев
  • Как мне убрать все эмодзи?

    @Flying
    Я в проекте для этой цели использовал пакет hidehalo/emoji, работает весьма неплохо.
    Ответ написан
    Комментировать
  • Зачем нужен flex-shrink и flex-grow, если есть процентный width и min-width?

    @Flying
    flex-shrink и flex-grow не имеют прямого отношения к размерам элемента в том плане что они не определяют размер напрямую (для этого есть flex-basis). Эти свойства определяют поведение элемента при сжатии (shrink) и расширении (grow).

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

    Более подробно можно почитать, например, на MDN (раз, два)
    Ответ написан
    Комментировать
  • Что почитать про правильное проектирование своих приложений?

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

    В целом, если вы хотите получше разобраться в паттернах проектирования - можно брать любую хорошую книжку по этой теме (те же Gang of Four, Мартин Фаулер (на русском) и т.п., предложенная Ярослав ссылка тоже выглядит весьма достойно), изучать, а затем пытаться найти эти паттерны в коде популярных и хорошо написанных проектов.

    Я несколько предвзят, но могу порекомендовать Symfony и Doctrine в качестве отправных точек. К примеру та же Doctrine прямо реализует целый пласт паттернов, описанных Фаулером. Symfony существенно более разнообразна, там можно встретить много различных решений.

    Изучение реализации паттернов в рамках конкретных реализаций позволит вам с одной стороны лучше понять сами паттерны, а с другой - лучше разобраться с тем как изнутри работают довольно сложные проекты, это позволит использовать их самих и, что ещё важнее, заложенные их идеи в вашем собственном коде.
    Ответ написан
    8 комментариев
  • Что не так при обращении к элементу так?

    @Flying
    Причина вашей проблемы в непонимании того как работает псевдо-класс :first-of-type. На Stack Overflow есть пара очень хороших объяснений этого, стоит ознакомиться (раз, два).

    Ключевым моментом для понимания должен стать тот факт что в контексте HTML понятие "element type" эквивалентно имени тега. Таким образом ваше ожидание что .services-block:first-of-type означает "первый элемент с классом services-block" ложно и это приводит к неработающему селектору. В реальности этот селектор читается как "любой подэлемент текущего элемента, имеющий класс services-block и при этом являющийся первым элементом с таким именем тега среди всех имеющихся". Слегка контр-интуитивно, да, но уж как есть.

    Вашу задачу можно решить если вы вспомните что div - не единственный элемент в HTML и начнёте использовать также и другие элементы. В вашем примере для div.basic-title и div.services-block_title явно лучше подходят какие-то из элементов заголовка, а структура из div.services-block_item и подэлементов - это явно dl/dt/dtt

    Простая замена заголовка на какой-либо Hx элемент позволит использовать селектор
    .container > div.services-container:first-of-type > .services-block:first-child
    .

    Также можно ничего не менять, тогда селектор получится несколько более жёстким:
    .container > .basic-title + .services-container > .services-block:first-child
    Ответ написан
    1 комментарий
  • Как скачать 12 миллионов фотографий Instagram?

    @Flying
    API для Instagram получить проблематично т.к. их родной API (который был до покупки их Facebook'ом) объявлен deprecated и по факту почти не работает, а новый, через Facebook, требует кучи подтверждений, да и вряд ли Facebook будут давать массово тянуть данные через API.

    Однако в случае Instagram это в целом и не надо т.к. сайт написан на React'е (и, в отличие от кучи мяса в коде Facebook'а написан очень чисто и современно), поэтому по факту сам процесс сбора данных в их случае крайне прост:
    1. Делаете запрос на страницу профиля
    2. В полученной странице ищите переменную _sharedData
    3. Разбираете её значение как JSON и достаёте нужную вам информацию, там будут первые посты со ссылками на их картинки
    4. Дальше идёте циклом про GraphSQL запросам (легко находятся через просмотр вкладки Network при скролле) и вытаскиваете остальное, данные курсора для интерации находятся в end_cursor.

    При запросе к GraphQL API нужно учесть одну особенность. Сейчас Instagram требует "подписи" запросов, делается это примерно так:
    headers.set('X-Instagram-GIS', md5(`${(window._sharedData || {}).rhx_gis}:${JSON.stringify(vard)}`));

    Переменная vars, передаваемая в JSON.stringify() - это содержимое поля variables из GraphQL запроса.

    Сам Instagram не банит за постоянные запросы, но если начинать наглеть - то включает throttling, начиная отдавать HTTP 429 в течении какого-то времени (до 5-10 минут), после чего всё движется дальше. Таким образом распараллеливание + прокси решают задачу довольно эффективно.
    Ответ написан
    8 комментариев
  • Как изменить URL в Symfony?

    @Flying
    Предположу что вы используете nginx в качестве веб-сервера в рамках Open Server.

    Если это так в этом случае public/.htaccess файл который реализует rewriting не срабатывает. Вам необходимо донастроить nginx для того чтобы он занимался преобразованием ссылок. Пример конфига есть в официальной документации.
    Ответ написан
    2 комментария
  • Есть ли сервисы для генерации регулярных выражений?

    @Flying
    Объединение всех фраз через | даст нужное регулярное выражение.

    Язык в вопросе не указан, так что пример на PHP:
    <?php
    
    $phrases = [
        'Hello world',
        'Lorem ipsum',
        'Just some test phrase',
        'Phrase with special "|" chars',
    ];
    
    $tests = array_merge($phrases, [
        'Some other text',
        'It should not match',
    ]);
    
    $regex = sprintf('/^%s$/i', implode('|', array_map(function ($v) {
        return preg_quote($v, '/');
    }, $phrases)));
    
    echo $regex . "\n";
    
    array_walk($tests, function ($phrase) use ($regex) {
        echo sprintf('%s: %s' . "\n", $phrase, preg_match($regex, $phrase) ? 'Matches' : 'Does not match');
    });
    Ответ написан