A
A
Aleksandr Yurchenko2019-08-23 22:30:37
OOP
Aleksandr Yurchenko, 2019-08-23 22:30:37

How to correctly implement the Parent->Child classes?

Hello.
Not so long ago I began to study OOP, so I'll forgive you not to judge strictly :)
We need to solve such a problem. There is a class:

class Subscribe

<?php declare(strict_types=1);
class SubscribeController
{
    public function notify(Request $request)
    {
        $email = $request->json('from.email');
        if (!isset($email)) {
            return self::userError('from.email is missing.');
        }
        if (!is_string($email)) {
            return self::userError('from.email must be a string.');
        }

        $name = $request->json('from.name');
        if (isset($name) && !is_string($name)) {
            return self::userError('from.name must be either null or a string.');
        }

        try {
            $mailer = Factory::createMailer(app()->basePath(), new EmailAddress($email, $name));
            $mailer->notify('тут название события', new EmailAddress('тут почта', 'тут имя'));
        } catch (Exception $e) {
            return self::error($e->getMessage());
        }

        return self::ok();
    }

    privat static function userError($message)
    {
        return self::error($message, 400);
    }

    privat static function error($message, $code = 500)
    {
        return response()->json($message, $code);
    }

    privat static function ok()
    {
        return response()->json("ok");
    }
}


Ранее событие было одно - подписка на новости, сейчас появились варианты (еженедельный дайджест, рассылка по категориями...). Соответственно нужно создать свой класс на тот или иное событие.
Так как в программирование занимаюсь от силы 6-7 месяцев и до этого шпарил исключительно на процедурке, первое что я сделал в такой ситуации - наговнокодил :) т.е. тупо скопировал содержимое этого класса, дал ему другое название и поменял тип события, фактически изменения (не считая переименования класса) были лишь в одной строке:
$mailer->notify('тут название события', new EmailAddress('тут почта', 'тут имя'));
Понял, что так дела не делаются, попытался вспомнить те статьи и видео, которые я смотрел по ООП (Где объяснялось: есть общий класс Животные, а есть классы Собака, Кошка и т.д.). Решил сделать нечто похожее. Сделать один общий класс SubscribeController и extends создать классы New, Didgest и т.д.
Переименовал приватные методы (обрабатывающие ошибки в protect), вынес в класс-родитель все что смог вынести и классы-потомки стали выглядеть примерно так:
Пример класса потомка

class Didgest extends SubscribeController
{
public function notify(Request $request)
    {
        $email = $request->json('from.email');
        if (!isset($email)) {
            return self::userError('from.email is missing.');
        }
        if (!is_string($email)) {
            return self::userError('from.email must be a string.');
        }

        $name = $request->json('from.name');
        if (isset($name) && !is_string($name)) {
            return self::userError('from.name must be either null or a string.');
        }

        try {
            $mailer = Factory::createMailer(app()->basePath(), new EmailAddress($email, $name));
            $mailer->notify('didgest', new EmailAddress('email', 'name'));
        } catch (Exception $e) {
            return self::error($e->getMessage());
        }

        return self::ok();
    }
}


Но даже тут видно, что копипасты крайне много осталось, фактически, в зависимости от типа события, мне нужно лишь менять название здесь:
$mailer->notify('--->NEW<---', new EmailAddress('email', 'name'));
   $mailer->notify('--->DIDGEST<---, new EmailAddress('email', 'name'));

Собственно подскажите, как можно убрать в класс-родитель(SubscribeController):
$email = $request->json('from.email');
        if (!isset($email)) {
            return self::userError('from.email is missing.');
        }
        if (!is_string($email)) {
            return self::userError('from.email must be a string.');
        }

        $name = $request->json('from.name');
        if (isset($name) && !is_string($name)) {
            return self::userError('from.name must be either null or a string.');
        }

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

Answer the question

In order to leave comments, you need to log in

2 answer(s)
Максим, 2019-08-23
@yaleksandr89

Паттерн диспетчер событий.
https://github.com/ElisDN/yii2-demo-shop/blob/mast...
Там где нужно вызвать https://github.com/ElisDN/yii2-demo-shop/blob/mast...
Обработчик https://github.com/ElisDN/yii2-demo-shop/blob/mast...
Зависимости через DI
https://github.com/ElisDN/yii2-demo-shop/blob/mast...

Григорий Васильков, 2019-08-23
@gzhegow

Вот как я понимал события

<?php

$events = [];

$on = function (string $name, callable $func) use (&$events)
{
  $events[ $name ][] = $func;
};

$fire = function (string $name, $emitter, ...$arguments) use (&$events)
{
  if (! isset($events[ $name ])) return;
  
  foreach ($events[ $name ] as $func) {
    call_user_func($func, $name, $emitter, ...$arguments);
  }
};

// когда машина выйдет с завода - поехали!
$on('car-created', function ($event, $car, ...$comments) { var_dump($car, $comments); });

// ...some application code

// пришло время, тачка готова.
$fire('car-created', $car, 'faster', 'darling');

Что тут есть. Есть массив, хранилище, где будут лежать инструкции $func "что сделать", привязанные на ключ $name - "когда сделать".
Есть функция $on, которая тупо на некое имя записывает в хранилище что делать.
Есть функция $fire, которая "стреляет" - начинает выполнять всё, что висит на этом `$name`. В параметре эмиттер может быть что угодно, что душе хочется - обычно это виновник торжества, из-за чего событие стрельнуло.
В аргументс тоже передаешь чего хочешь, параметры массивы и так далее.
Вот когда понимаешь что события, это вот так вот просто, сверху можешь на них навесить классы, чтобы понять что эвентс лучше хранить в классе "Диспетчер", а типы событий тоже могут быть классами вместо `$name`, тогда в них можно какие-то функции зашить внутрь.
Пока просто вот так отнесись к этому

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question