• Как программировать PHP/MYSQL чтобы потом можно было синхронизировать БД?

    @EvgeniiR
    https://github.com/EvgeniiR
    Что и с чем синхронизировать?
    Чтобы id не пересекались на нескольких нодах можно использовать UUID.
    Можно ещё всякое типа microtime+идентификатор ноды, но вряд ли нужно без каких-то серьёзных требований по производительности
    Ответ написан
    6 комментариев
  • Есть ли аналоги или плагина для редактирования текста как на ресурсах vc.ru в статьях Вконтакте или Pikabu?

    @EvgeniiR
    https://github.com/EvgeniiR
    Это WYSIWYG-редакторы. Так и гуглите. Вот, например, клон медиума - https://github.com/yabwe/medium-editor (demo).
    Ничего сложного там нет - под капотом текст с определёнными тегами, с которым работает редактор, и умеет отдавать(для сохранения) и принимать(отображать).
    Ответ написан
    1 комментарий
  • В каких случаях при разработке сайта на PHP лучше использовать не MVC (и его подобия), а какой-нибудь другой подход?

    @EvgeniiR
    https://github.com/EvgeniiR
    В каких случаях при разработке сайта на PHP лучше использовать не MVC (и его подобия), а какой-нибудь другой подход?

    В случаях когда разработчики проекта разбираются в разных подходах и знают какой лучше использовать.
    Во всех остальных случаях лучше этого не делать.

    Большинство даже в MVC никогда не пыталось разобраться, и думает что это когда в проекте 3 папочки есть(model/ view/ controller/).
    Или что MVC было придумано для веб приложений (а это не так :) ).
    Ответ написан
    8 комментариев
  • Зачем нужно ООП?

    @EvgeniiR
    https://github.com/EvgeniiR
    Разберитесь с разницей между ООП и процедурным программированием для начала.
    ООП в формулировке "Инкапсуляция, Наследование и Полиморфизм" может и не нужно.
    Объектно-ориентированный дизайн как инструмент декомпозиции нужен чтобы контролировать сложность системы.

    И вообще, вы хотите чтобы вам тут в двух словах разобрали тему многих книг и публикаций. Так не бывает.

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

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

    Впрочем, если вам этот ответ что-то даст:
    Цель ООП - управление сложностью ПО.
    Ответ написан
    1 комментарий
  • RabbitMQ: что такое exchange, и где его место?

    @EvgeniiR
    https://github.com/EvgeniiR
    Exchange это просто посредник который решает как роутить сообщения в очереди, тем самым отвязывая немного продюсер от знания как и кем будут сообщения обрабатываться.

    Нужно ли выносить в отдельный файл exchange, и стучаться к нему при отправке сообщения, или можно оставить в коде продюсера ?

    Что значит "выносить exchange в отдельный файл"? Exchange он в брокере.

    Продюсеру нужно лишь имя exchange знать чтобы сообщения туда постить, и Routing Key при необходимости.
    Создавать exchange лучше конечно не в продюсере.

    Чтобы перестраховаться и убедиться что exchange существует можно, конечно, отправить сообщение с объявлением exchange с флагом passive( https://www.rabbitmq.com/amqp-0-9-1-reference.html... )
    Ответ написан
    3 комментария
  • Можете ли оценить код, и сказать как сделать его лучше?

    @EvgeniiR
    https://github.com/EvgeniiR
    1. Type hints для свойств через phpdoc использовать. Или обновиться до 7.4 и использовать type-hints средствами языка.
    2. Type hints для аргументов методов и возвращаемых значений использовать.
    3. Написать класс Logger и использовать как зависимость. Желательно чтобы он был адаптером для LoggerInterface(psr3)
    4. Методы и переменные нормально называть, половину пхп-доков повыпиливать.
    5. Логику(ветвления) либо выносить в зависимости, либо писать юнит-тесты на неё. Учитывая что этот класс ещё и в базу лазит через AR, логики(ветвлений) тут лучше не делать.
    6. $value передавать не в конструктор а в конкретные методы где оно нужно, чтобы не пересоздавать экземпляр класса для каждого списания.
    7.
    private function initiator($system = true){
        if ($system){
            return User::find()->where(['login'=>'System'])->one();
        }
        return Yii::$app->user->identity;
    }


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

    5. это вы имеете ввиду что в методах new используется?

    Да, внедряйте зависимости через Dependency Injection. То есть не создавайте new CashLog а требуйте экземпляр логгера с нужными вам методами в конструктор. Если логгеру нужен юзер а у вас в классе только его идентификатор - желательно бы передавать в логгер идентификатор, а дальше пусть его забота будет, чтобы не нагружать этой логикой ваш класс.
    В принципе о связности/тестируемости вам рановато пока думать, в будущем стоит присмотреться к принципам Coupling/Cohesion.
    Ответ написан
    Комментировать
  • Как организовать архитектуру мероприятий?

    @EvgeniiR
    https://github.com/EvgeniiR
    Немного о будущих цифрах:
    Организаций: ~ 2000
    тренеров: ~ 15000
    спортсменов: ~ 25000
    Заявок: ~ 100000 в год

    С нагрузками проблем не будет, не беспокойтесь.

    Возможно следует сделать один сервис Мероприятия, который будет объединять в себе всё это?

    Да. Микросервисы про независимую разработку разными командами и независимый деплой.
    Для разработки приложения в одиночку они не нужны совсем. Это огромное усложнение впустую.

    Тогда как организовать лучше слабую связанность в сервисе, чтобы можно было менять одну регистрацию на другую?

    Внутри монолита приложение так же прекрасно разбивается на модули/контексты, как и в микросервисах.

    Например, сделали новую регистрацию v2.0 и теперь нужно заменить. Или дописали новую - нужно добавить. Интерфейсы?

    Да, интерфейсы, IoC, контроль зависимостей, декомпозиция, итеративное проектирование и рефакторинг.

    Имеет ли смысл регистрацию и счёты разделить на свои отдельные сервисы.

    Имеет смысл ложить вместе те данные, которые вместе меняются и используются. Постарайтесь ответить для себя на этот вопрос. Так же помните что лучший выбор решения - не выбирать а отложить на потом.

    3. Имеет ли смысл делать общий сервис Person? Или в каждом сервисе добавить Member, Teacher, Artist Organizator?

    Сквозной функционал между сервисами это плохо т.к. плодит зависимости и влечёт каскадные изменения после каждой правки. Делаете сервисы так чтобы им не было важно, Teacher там, Member или Artist.

    От монолита точно стоит уходить.

    Нет.

    p.s. Хотите использовать что-то крутое и сделать ваш проект лучше и качественнее - пишите unit-тесты.
    Ответ написан
    3 комментария
  • Как правильно задавать свойства классам php?

    @EvgeniiR
    https://github.com/EvgeniiR
    Правильно - задавать свойства в конструкторе класса. А публичные поля или методы get/set это нарушение инкапсуляции.
    Экземпляр класса должен полноценно работать и иметь в себе все необходимые для работы данные сразу после его создания.

    Есть исключения когда мы имитирируем структуры данных через классы-DTO(В PHP нету встроенных типов структур/data-классов), но заполнение и там должно быть через конструктор.

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

    На Тостере много чего пишут, не стоит всему верить, точнее стоит ничему не верить, а анализировать :)
    В плане каких-то конкретных терминов часто можно узнать очень много интересных вещей загуглив первоисточник термина/историю появления(в т.ч. причины).

    Постарайтесь определить цели и понять как эти варианты помогают вам эти цели достичь. А "правильных" вариантов без заданной цели не может быть.
    В будущем в этом плане стоит смотреть на концепты Coupling/Cohesion, и почему они важны(книжки Clean Architecture, Clean Code и т.п., так же принцип Low Coupling + High Cohesion входит в паттерны GRASP).

    По теме - задавая параметры через set() методы мы:
    - Подразумеваем что все пользователи нашего класса знают какие у него параметры, и более того - что они означают. Это создаёт большую нагрузку на пользователей класса, усложняет клиентский код.
    - Позволяем в любом месте где используется класс поменять что-то внутри, и неожиданно обнаружить ошибки в других местах системы. А ещё настройки могут конфликтовать друг с другом, и одни свойства зависеть от других. Установка одного поля может требовать установки другово, и такие вещи стоит указывать на уровне интерфейса, то есть сделать вместо условных setStartDate() и setEndDate() метод setDatePeriod(DatePeriod period), даже если внутри класса это два поля.

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

    И ещё - есть разница между методами которые меняют состояние класса, и конкретно "сеттерами". Семантика важна. То что внутри класса что-то меняется нас не интересует. Нам важно лишь чтобы выполнилось то, что мы ожидаем от класса. Если мы хотим обновить статью, мы вызовем метод updateArticle(), или какой-нибудь changeTitle(), например. Если мы хотим кофе мы скажем машинке makeEspresso(), а не будем указывать количество зёрен, упростив таким образом клиентский код.
    Ответ написан
    1 комментарий
  • Как правильно реализовать создание дочерних экземпляров класса?

    @EvgeniiR
    https://github.com/EvgeniiR
    Как то так
    class UserData {
        /**
         * @readonly
         * @var string
         */
        public $source;
    
        public function __construct(string $source)
        {
            $this->source = $source;
        }
    }
    
    class NoSupportingSenderFound extends \Exception {}
    class AnswerTransportError extends \Exception {}
    
    interface AnswerSender {
        public function supportSource(string $source): bool;
    
        /**
         * @throws AnswerTransportError
         */
        public function sendAnswer(string $answer): void;
    }
    
    class AnswerSenderFacade
    {
        /**
         * @var AnswerSender[]
         */
        private $senders = [];
    
        public function __construct(AnswerSender ... $answerSenders)
        {
            $this->senders = $answerSenders;
        }
    
        /**
         * @throws AnswerTransportError
         * @throws NoSupportingSenderFound
         */
        public function sendAnswer(UserData $userData, string $answer)
        {
            foreach ($this->senders as $sender) {
                if($sender->supportSource($userData->source)) {
                    $sender->sendAnswer($answer);
                    return;
                }
            }
            throw new NoSupportingSenderFound("...");
        }
    }


    В конструктор класса AnswerSenderFacade нужно передать инстансы всех реализаций интерфейса AnswerSender. В Symfony это просто делается через tagged services (Навесить тег на _instanceof AnswerSender через конфиг и в конфиге же указать что все помеченные тегом классы нужно заинжектить)

    Над названием конечно можно ещё подумать.

    p.s. в случае Симфони, правда, в конструкторе вместо ...$providers придётся использовать iterable и дополнительно проверять что пришли инстансы SenderInterface через instanceof
    Ответ написан
    4 комментария
  • Какие ресурсы прочитать или, может, книги,где описаны приемы проектирования ядра приложения?

    @EvgeniiR
    https://github.com/EvgeniiR
    Первое правило проектирования ядра приложения - избавиться от ядра приложения и делать нормальные компоненты с минимумом зависимостей.

    Второе правило - прочитать что такое God Object и потихоньку начать понимать причину избавления от ядра.

    Третье правило - пойти читать Чистую Архитектуру/Чистый код, разобраться с концептами coupling/cohesion и т.п.

    p.s. последовательная обработка данных множественными компонентами может решаться через сервисы - координаторы, через посредники(middlewares), цепочку обязанностей(Chain Of Responsibility), хоть декораторы в конце концов.
    Ответ написан
    2 комментария
  • Книги, помогающие научиться правильно именовать классы?

    @EvgeniiR
    https://github.com/EvgeniiR
    В чем моя проблема?)

    В том что ваш класс делает слишком много и знает слишком много.
    Ни про какие "3 уровня обработки" данных которые к нему приходят он знать не должен.
    Он принимает данные определенного формата и возвращает данные определенного формата. Что с ними происходило для и что будет происходить после его не волнует.

    Если невозможно выразить на уровне типов все требования к входящим данным, класс возвращает ошибку если данные пришли не в том виде, в котором он ожидал.

    какие книги ставят голову на место в этом плане?

    Почитать - Макконнелл, "Совершенный Код". Книжка толстая, но не сложная технически, любые нюансы именования там описаны.
    Ну и в дальнейшем исходить из вопросов "для чего я это делаю?" и "какие ещё есть варианты это делать?"
    Ответ написан
    2 комментария
  • Как правильно получить составные данные из базы и сложить их в одну сущность?

    @EvgeniiR
    https://github.com/EvgeniiR
    Немножко не ответ
    Для класса PostsModel:
    Автор Поста является потомком Поста.
    Пост для автора - Родитель.
    Пост для даты поста - Родитель.

    *Тут была реплика про уровень комьюнити тостера, и даже "Кураторов Тега", которые позволяют себе нести вышепроцитированную чушь, но я решил её опустить, т.к. разумный человек и так поймёт со временем*

    Совет - развивайте критическое мышление и фильтруйте информацию, не верьте всему в интернете, даже если у этого 100500 плюсов на каком-нибудь ресурсе типа Хабра/SO/Medium/Тостер и т.п.


    Алексей Коновалов,
    нам нужна одна точка получения данных.

    Нам не нужна "единая точка получения данных". У вас есть ваши модели(сущности, доменные модели) - это компонент вашей системы отвечающий за часть бизнес-логики.
    Так же у вас есть представления данных. Представлений данных может быть множество. Не нужно реиспользовать одну и ту же модельку для логики/записи и для чтения(представления, UI).
    Выбрали данные из БД(raw SQL/Eloquent/DQL смапленный на DTO, что угодно)
    ->заполнили ими структуру которая сформирована исходя из нужд клиентского модуля(Frontend`а вашего),
    -> привели к нужному формату(json etc.) и отдали на фронтенд

    Он работает с базой данных и делает все, что связано с постами. И тут как раз проблема.

    Очень хорошо что вы подметили что это проблема, серьёзно. Именно по этому "Active Record" - антипаттерн.
    Некоторые, к большому сожалению, годами к этому не могут придти, того больше - отстаивают каждое архитектурное решение какого-нибудь Laravel не с позиции инженера, а с позиции религиозного фанатика.

    Модели для записи ничего про HTTP, Request и представления знать не должны. Модели на чтение по сути просто структуры данных.
    Ответ написан
    Комментировать
  • Как провалидировать jsonShema?

    @EvgeniiR
    https://github.com/EvgeniiR
    Чтобы запретить присылать лишние поля, вам нужно описывать объекты в схеме, объявлять их свойства(properties) и указывать в схеме параметр additionalProperties => false

    Пример из документации

    {
      "type": "object",
      "properties": {
        "number":      { "type": "number" },
        "street_name": { "type": "string" }
      },
      "additionalProperties": false
    }


    https://json-schema.org/understanding-json-schema/...
    Ответ написан
  • Стоит ли сейчас читать Стива Макконнелла - Совершенный код?

    @EvgeniiR
    https://github.com/EvgeniiR
    Вобщем, ответ на ваш вопрос - это на первый взгляд в IT все бежит, если углубиться, все эти новые js или не js фреймворки это малая доля от того что нужно знать и что меняется, а на фундаментальном уровне за 20 последних лет ничего кардинально не меняется. Книги по конкретным фреймворкам которые не вносят чего-то необычного (типа actor model) и современные читать смысла не много(ибо дока + паттерны под капотом и архитектурные правила те же что и раньше), а чтобы понять какой-нибудь MVC(а большинство не понимает что это такое аля "создал папочку контроллеры значит MVC т.к. так на Хабре пишут") и сейчас читать записи 70-х годов по сути необходимо, если вдруг когда-нибудь захочется углубиться, конечно. Тоже самое с очень многими темами.
    P.s. В общем, читать Совершенный Код исключительно хорошее занятие, как и Рефакторинг от Фаулера например :)
    Ответ написан
    1 комментарий
  • По какому пути вы бы пошли при рефакторинге?

    @EvgeniiR
    https://github.com/EvgeniiR
    3) Сделать новый класс AdvancedBalance унаследовать от Balance и переопределить метод getBalance

    4) Сделать новый класс AdvancedBalance унаследовать от Balance и создать новый метод getAdvancedBalance,

    Ох уж эти ООП-девелоперы. Ради чего вы там наследовать собрались?
    Добавьте интерфейс NumberFormatter или BalanceFormatter, прогоняйте числа через них в нужных местах.

    молится что ничего не сломалось

    хоть тесты и есть

    Они не просто "есть", их ещё и поддерживать нужно. Пойдите по пути написания тестов на места которые могут поломаться.

    с принципом открытости закрытости, который рекомендует расширять классы для добавления новой функциональности.

    Расширять, а не наследовать, принцип о том чтобы менять как можно меньше кода, в идеале вообще не трогать, а вы, якобы следуя ему, предлагаете пол проекта перелопатить для использования другого интерфейса

    p.s. Гляньте, например, https://www.youtube.com/watch?v=pu0EXQvoaCc
    Ответ написан
    Комментировать
  • Можно ли сократить код?

    @EvgeniiR
    https://github.com/EvgeniiR
    /**
     * @param Text|TextRun $arg
     */
    function printText($arg): void {
      if($arg instanceof TextRun) {
        foreach($arg as $el) { printText($el); }
      } elseif ($arg instanceof Text) {
        echo $arg->getText();
      } else { 
        throw new \InvalidArgumentException('...');
      }
    }
    Ответ написан
    Комментировать
  • Как в Symfony создать форму в форме?

    @EvgeniiR
    https://github.com/EvgeniiR
    1. Не связывать формы с Entity 1к1.
    2. Официальная спецификация HTML/XHTML не позволяет иметь вложенные формы.

    И вообще - https://www.youtube.com/watch?v=WW2qPKukoZY
    Ответ написан
    Комментировать
  • Chain Of Responsibility vs Event Bus, в чем принципиальная разница?

    @EvgeniiR
    https://github.com/EvgeniiR
    1. Если нужен порядок обработки в event bus, возможно у вас в системе есть проблемы(см. Temporal coupling)

    2. Да, паттерны решают похожие задачи, есть разница в децентрализации. В Chain if responsibility есть менеджер который который цепочку вызывает по порядку.
    В то время как event - событие, факт, один модуль кидает ивент и ему нет никакого дела кто будет его обрабатывать и кому этот ивент интересен.
    Обработчики ивентов не знают друг о друге и никак на другие обработчики не полагаются, и ни один обработчикик не может остановить дальнейшую обработку события. (Поэтому ивенты в js с их stopPropagation(), или "events" в некоторых фреймворках не совсем ивенты).
    Ответ написан
    1 комментарий
  • Плоха ли описанная архитектура, для laravel?

    @EvgeniiR
    https://github.com/EvgeniiR
    Что вы подразумеваете под пакетами?

    если нужно что то исправить то идем в конкретную папку и правим там. не нужно размазывать код, одного большого элемента, по всему фреймворку

    То что фреймворк по дефолту генерирует папочки Controller Model View, не значит что обязательно их использовать именно в таком виде. Делите проект на логические модули, выделяйте модули в отдельные папки со своими моделями и контроллерами.
    Делать 3 папки-свалки с контроллерами/моделями/видами очень плохая идея в плане навигации контроля связности и зависимостей между модулями
    См. Структура проекта

    Чем это хуже подхода - когда вся логика распологается в сервисах, и в целом чем плох такой подход?

    Логика в сервисах это большая связность чем нормально спроектированная доменная модель.
    Про бизнес-логику в сервисах см. Anemic Domain Model

    но стандарт MVC

    MVC это не стандарт и ничего общего эта аббревиатура со структурой папок не имеет
    Ответ написан
  • Если ключ составной, будет ли поиск по одному столбцу?

    @EvgeniiR
    https://github.com/EvgeniiR
    Если индекс из двух полей, он будет использоваться при поиске по первому полю и при поиске по обоим полям(в поиске только по второму полю он использоваться не будет)
    Ответ написан
    2 комментария