Если вы когда-нибудь пытались развивать проект, который начинался как «просто сайт-визитка», а через год превратился в монстра с десятками контроллеров и моделей, то знаете: без чёткой структуры код превращается в кашу. Сегодня расскажу, как этого избежать с помощью модульной архитектуры в Yii2. Спойлер: это проще, чем кажется, и спасёт вам нервы.

Digital-студия WNDER

Модуль в Yii2 — это как отдельная комната в квартире. В ней есть своя мебель (контроллеры), свои вещи (модели), свои правила (конфиги). И всё это изолировано от других комнат, но при этом легко доступно через общий коридор — приложение. Звучит логично, правда? Давайте разберёмся, как это реализовать на практике.

Почему модули — это не роскошь, а необходимость

Когда вы работаете над проектом, который планирует расти (а кто не планирует?), рано или поздно столкнётесь с проблемой: файлы разрастаются, связи между ними запутываются, а правки в одном месте ломают другое. Модульная структура решает эти проблемы раз и навсегда.

  • Изоляция. Каждый модуль отвечает за свою часть функциональности. Например, модуль «каталог» не знает о существовании модуля «корзина» и не должен в него лезть.
  • Переиспользование. Модуль можно легко перенести в другой проект или отключить, если он больше не нужен.
  • Тестирование. Модули можно тестировать независимо друг от друга, что упрощает поиск ошибок.
  • Командная работа. Если над проектом работает несколько разработчиков, каждый может заниматься своим модулем, не конфликтуя с другими.

Без модулей вы рано или поздно упрётесь в «спагетти-код», где всё связано со всем. Поверьте, я видел такое не раз. И это не лечится, кроме как полной переработкой.

Правило: Если функциональность проекта можно разделить на независимые блоки (каталог, корзина, пользователи, админка) — значит, это повод для модулей. Не ждите, пока станет больно.

Создаём модуль: пошаговая инструкция

В Yii2 модуль — это обычная директория с файлами. Создавать его можно вручную или через консольную команду. Покажу оба способа.

Способ 1: Через консоль (быстро и удобно)

php yii gii/module --moduleID=blog --moduleClass=app\modules\blog\BlogModule

Эта команда создаст модуль с именем «blog» в папке modules. Внутри появятся стандартные папки: controllers, models, views и файл BlogModule.php.

Способ 2: Вручную (для полного контроля)

  • Создайте папку modules в корне приложения, если её ещё нет.
  • Внутри создайте папку модуля, например blog.
  • Создайте файл BlogModule.php с классом модуля.
namespace app\modules\blog;

class BlogModule extends \yii\base\Module
{
    public $controllerNamespace = 'app\modules\blog\controllers';

    public function init()
    {
        parent::init();
        // здесь можно инициализировать модуль
    }
}

Теперь подключите модуль в конфигурации приложения. Откройте config/web.php и добавьте:

'modules' => [
    'blog' => [
        'class' => 'app\modules\blog\BlogModule',
    ],
],

Готово! Модуль доступен по адресу /blog. Если вы создали контроллер PostController с действием index, то адрес будет /blog/post/index.

Параметр Описание
controllerNamespace Указывает, где искать контроллеры модуля.
defaultRoute Определяет контроллер и действие по умолчанию (например, 'post/index').
layout Можно задать свой макет для модуля, если нужно.

Как правильно организовать код внутри модуля

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

  • controllers — только контроллеры. Никакой бизнес-логики, только обработка запросов.
  • models — модели, которые отвечают за работу с базой данных (ActiveRecord).
  • views — представления (HTML-шаблоны).
  • widgets — виджеты, если они специфичны для модуля.
  • components — вспомогательные классы, например, сервисы или хелперы.
  • assets — CSS/JS файлы модуля, если они есть.
  • migrations — миграции для таблиц модуля.

Важно: не выносите логику в контроллеры. Если вы замечаете, что контроллер становится «толстым» — значит, пора вынести часть кода в отдельный класс. Например, в сервис.

// Пример сервиса в модуле blog
namespace app\modules\blog\components;

use app\modules\blog\models\Post;

class PostService
{
    public function createPost($data)
    {
        $post = new Post();
        $post->attributes = $data;
        $post->author_id = \Yii::$app->user->id;
        $post->save();
        return $post;
    }
}

Контроллер в этом случае будет тонким:

namespace app\modules\blog\controllers;

use app\modules\blog\components\PostService;
use yii\web\Controller;

class PostController extends Controller
{
    public function actionCreate()
    {
        $service = new PostService();
        $post = $service->createPost(\Yii::$app->request->post());

        return $this->redirect(['view', 'id' => $post->id]);
    }
}
Лайфхак: Если вы замечаете, что в контроллере больше 20 строк логики — это звоночек. Выносите её в сервисы или компоненты. Так вы сохраните чистоту и упростите тестирование.

Связываем модули между собой: без фанатизма

Модули не должны знать друг о друге. Но иногда им нужно взаимодействовать. Например, модуль «каталог» должен показывать цену товара, которую считает модуль «цены». Как быть?

Есть несколько способов:

  • Через события. Один модуль генерирует событие, другой его слушает и реагирует.
  • Через общий сервис. Выносите общую логику в отдельный компонент приложения, который доступен всем модулям.
  • Через URL и API. Модули могут общаться через HTTP-запросы, если это уместно.

Я предпочитаю второй вариант. Создайте компонент, например, PriceManager, который будет доступен через Yii::$app->priceManager. Тогда любой модуль сможет получить цену, не зная деталей реализации.

// В конфигурации приложения
'components' => [
    'priceManager' => [
        'class' => 'common\components\PriceManager',
    ],
],

И в любом месте:

$price = Yii::$app->priceManager->getPrice($productId);

Это проще и надёжнее, чем создавать жёсткие зависимости между модулями.

Советы по масштабированию: как не выстрелить себе в ногу

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

  • Начинайте с модулей сразу. Не ждите, пока проект разрастётся. Создайте модуль для первой же функции, даже если она маленькая.
  • Используйте миграции для каждого модуля. Храните миграции внутри модуля, чтобы при переносе модуля в другой проект таблицы создавались автоматически.
  • Не злоупотребляйте вложенностью. Модуль внутри модуля — это редко бывает оправдано. Лучше создать отдельный модуль.
  • Следите за зависимостями. Если модуль использует классы из другого модуля напрямую — это плохо. Старайтесь изолировать.
  • Пишите тесты для модулей. Это спасёт вас при рефакторинге. Хотя бы минимальные.

Не бойтесь экспериментировать. Модульная структура — это не догма, а инструмент. Подстраивайте её под свой проект, и она будет работать на вас.

Что в итоге

Модульная структура в Yii2 — это не просто модный тренд, а реальный способ держать проект в порядке. Вы получаете изоляцию, переиспользуемость и лёгкость поддержки. Главное — начать с малого и не усложнять.

Если вы только начинаете — создайте один модуль для теста. Посмотрите, как он работает. Потом добавьте второй. Через пару недель вы не поймёте, как жили без этого.

Удачи в разработке, и пусть ваш код всегда остаётся чистым!

Студия WNDER