PHP разработчик и руководитель небольшого интернет-магазина.
Работаю с Symfony.

Помогаю чем могу новичкам.

Провожу вечерние/выходные занятия в Москве:
Живые уроки по разработке на PHP
Помогу начинающим PHP-программистам, мануальным тестировщикам и начинающим фронтенд-разработчикам освоить серверную разработку на PHP.

Пишу в блог:
Абстракции и как они текут
Как джуниор-разработчику найти работу (vc.ru)
Тестовые задания для джуниоров PHP
Контакты
Местоположение
Россия, Москва и Московская обл., Москва

Достижения

Все достижения (57)

Наибольший вклад в теги

Все теги (220)

Лучшие ответы пользователя

Все ответы (780)
  • ValueObject - зачем?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Такой Value Object ВИДИМО создали, чтобы логику например его создания не городить в самих сущностях, например у этого VO может быть свой специфичный конструктор. Также у этого объекта возможны методы направления сортировки, вплоть до самых интересных -- эти знания тоже могут быть лишними для нашей сущности... Много чего может быть, вплоть до того, что нужно смотреть на некие другие данные и строить стратегию сортировки. И чтобы не нарушать SRP -- эту всю логику вынесли в самостоятельный объект, который не является сущность, значит в общепринятых терминах -- это VO.

    Такое может быть с чем угодно -- с датами, с метатегами (объект Meta для разных сущностей будет как правило с одной сиггатурой), для Id и даже может быть объект Name (в нем могут быть формирования коротких, длинных, сокращённый и всевозможных других состояний)

    Если у вас есть вопрос, замечу -- резонный, то вам такая абстракция просто напросто не нужна в силу простоты этого узла системы. Используйте int, но назовите тогда понятным свойством, например position или priority
    Ответ написан
  • Какой использовать паттерн проектирования для интеграции c внешним сервисом?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Не складывается все пока в единую структуру

    Глаза боятся, руки делают

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

    Допустим вы под таким сервисом понимаете сервис доставки -- такой сервис в будущем понадобится подменить, заменить и т.д... Там есть и работа с пользователями и с заказами.

    Простой набросок со Стратегией

    Можно придумать некий интерфейс клиента:
    // Принимает ваши учетные данные
    DeliveryClientInterface::__construct(?string $account = null, ?string $password = null)
    
    // Регистрируем покупателя в сервисе
    DeliveryClientInterface::registerCustomer(DeliveryCustomer $customer): int
    
    // Получаем заказы покупателя в сервисе
    DeliveryClientInterface::getOrders(int $customerId): DeliveryOrder
    
    // Добавляем заказ покупателю
    DeliveryClientInterface::addOrder(int $customerId, DeliveryOrder $order): int
    
    // Оповещение покупателя в сервисе о неком действии, связанной с ним в этом сервисе
    DeliveryClientInterface::notifyCustomer(DeliveryEvent $event): bool


    И научить свой проект работать с таким кодом, через интерфейсы
    // что в конструктор сервиса запихнете, например PochtaClient или PickPointClient,
    // с тем и будете работать
    class DeliveryService
    {
        public function __construct(DeliveryClientInterface $deliveryClient, User $user)
    }
    
    $userOrders = $this->deliveryService->getOrders($user->getUuid());


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

    Далее в клиентском коде подключайте нужный вам клиент через конфиг/контейнер и все будет работать.
    Ответ написан
  • Зачем нужен ActiveQuery в Yii2?

    Maksclub
    @Maksclub
    maksfedorov.ru
    Если быть более, конкретным, зачем нужна эта опция, при генерации модели через Gii?

    Чтобы вы могли добавить свои кастомные методы или переопределить родные (all(), one() и другие, короче переопределить родной ActiveQuery и изменить на свои абстракции)

    Вот пример контроллера:
    actual() -- такого метода нет в ORM, а мне нужен, ну вот хочу так пользоваться:
    $trainings = Training::find()->actual($date);

    ActiveQuery

    Ну раз нужен -- добавляем такой метод
    class TrainingQuery extends \yii\db\ActiveQuery
    {
        public function actual($date)
        {
            return
                $this->alias('t')
                ->joinWith(['lesson l' => function($q){
                    $q->joinWith('studio s');
                }])
                ->andWhere(['l.active' => 1])
                ->andWhere(['s.active' => 1])
                ->andWhere(['t.date' => $date])
                ->all();
        }
    }

    Сущность

    В сущности перенацеливаем родной find() на мой кастомный
    class Training extends \yii\db\ActiveRecord
    {
    ...
    public static function find()
        {
            return new \mynamespace\entities\query\TrainingQuery(get_called_class());
        }

    Ответ написан
  • Может ли модель работать с массивом _POST и записывать данные в сессию?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    • в модель должны попадать чистые данные (то есть таки да - -в контроллере)
    • вообще с голым _POST не нужно в 2018 году работать, посмотрите это видео: https://vk.cc/8dAijK
    • валидацией может заниматься модель, но в данном случае МОДЕЛЬ ВАЛИДАЦИИ, а не модель сущности,
      модель -- это целый слой, а не конкретный класс или вид классов, это и сущности и сервисы и валидация и т.д....

    POST в моделе
    Не правильно работать с _POST в моделе, тк модель -- по сути синоним вашего бизнеса, бизнес модель, мне кажется странным было бы, если в магазине были бы продавцы, товары, операции дать денег и взять сдачу, данные (купюра, скидка)
    и тут же некий _POST запрос (ну или некая звуковая информация для операций (с битрейтом и частотой:):) мне кажется в бизнес-процесс должно попадать число или купюра, которое обработает некий контроллер (глаз, ухо и продавец в целом как валидатор)

    Валидация в сеттере
    По поводу сеттеров и валидации -- тоже плохо
    Купюра должны быть проверена в момент ее передачи, а не когда вы уже дали товар, посчитали сдачу, напечатали чек).. аналогия может быть немного не точной, но понятен принцип -- не в сеттере :)

    Ну или как пример -- договор между юрлицами, когда вы договорились и заполняете договор, для подписей (по сути сеттер ваш абстрактный) вы УЖЕ ДОЛЖНЫ были проверить контрагента и условия этого самого договора

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

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

    Смотрите как валидация делается в Ларавел:
    public function rules()
        {
            return [
                'name' => 'required|string|max:255',
                'email' => 'required|string|email|max:255|unique:users',
                'password' => 'required|string|min:6|confirmed',
            ];
        }
    Ответ написан
  • Передаю через AJAX клиенту с помощью ф-ии "file_get_content" содержимое php файла (для вывода в popup). В popup пишется также php код. Как исправить?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Кто знает, может, это можно по-короче написать?

    ob_start();
    include(VIEWSPATH . 'pages/login' . '.php');
    return $this->render_ajax(ob_get_clean();


    ob_get_clean() по сути выполняет ob_get_contents() и ob_end_clean().
    php.net/manual/ru/function.ob-get-clean.php
    Ответ написан

Лучшие вопросы пользователя

Все вопросы (40)