Pull to refresh
11

Программист, техлид

3
Subscribers
Send message
репозиторий обычно возвращает значение как инстанс ActiveRecord

Да, часто именно так и происходит. Потому что так удобно.

Тут вопрос приоритетов: либо нам нужно быстро, тогда ActiveRecord, либо нам нужно надолго, тогда делаем модели пассивными, а вся работа с хранилищем идёт через репозитории.
Так и есть. Поэтому, если мы придерживаемся принципов чистого кода, нам приходится изолировать нашу систему от грязного внешнего мира. А для этого абстракции нам в помощь.
Кстати, Samdsrk на одной из недавних конференций признавал ActiveRecord не самым удачным патентном с точки зрения чистоты кода.
Вы вызываете старый метод из нового?

Нет. Я говорю о методах контроллера, о тех, которые action. Вызвать один из другого не предполагается. Они должны работать параллельно, вызывая наш ClientClass. Причем функциональность первого action'а должна остаться как есть, а функциональность второго необходимо расширить.

Вообще наверно наоборот должно быть, старый метод должен вызывать новый, который более гибкий, с нужными настройками.

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

Ну так это ж стандартная настройка ActiveQuery, как в любой форме с фильтрами. Тут не требуется писать поверх этого дополнительную абстракцию.

Дополнительная абстракция в нашем случае необходима, чтобы изолировать изменяемую часть кода (применение дополнительных условий к ActiveQuery) от неизменяемой (код ClientClass). Поэтому мы вносим ее в отдельную группу классов filter.
Можно. В комментарии ниже, например, предлагают использовать репозитории.
Вот конкретный пример из моего проекта.

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

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

Предполагается, что код клиентского класса в моем примере как раз работает на уровне репозитория.
По поводу фильтров, мы юзаем github.com/Happyr/Doctrine-Specification
У репозитория есть метод match()...

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

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

Да. Классы фильтров тоже можно называть человекопонятно.
иногда фильтров может не хватить. Тогда в класс BookFilters придется чего-нить дописать.

А вот эту граблю мы можем обойти, используя ООП: с классами разделение получается несколько лучше. Но с другой стороны, у вас изоляция на уровне функций, у меня — на уровне классов. Так что по сути, повторюсь, ваш пример почти полностью аналогичен моему.
Внешний код — не большая проблема. Мы всегда можем изолироваться от него. А вот поддержание чистоты в собственной кодовой базе — это уже наша ответственность.
Закрытость — она больше в голове, на уровне соглашений.
В данном случае мы делаем удобнее сделать правильно (написать класс фильтра), чем неправильно (лезть с правками в исходный метод). Но, конечно, при большом желании накосячить никто никому не запретит.
Очень резонные вопросы.
как правильно заполнять filters (например фабричный метод)

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

Тут опять же есть варианты. Метод типа addFilter(ActiveQueryFilter $filter). Либо сеттер с проверкой типов. Либо проверка предусловий перед применением фильтров. Этот вопрос, пожалуй, мог бы протянуть на отдельную статью.

Information

Rating
Does not participate
Location
Россия
Registered
Activity

Specialization

Бэкенд разработчик
Ведущий