Представьте, что вы строите дом. Если класть кирпичи как попало, стены рухнут. В программировании то же самое. Без модульной архитектуры ваше приложение превращается в кашу из файлов. Сегодня я покажу, как навести порядок в Yii2 с помощью модулей. Вы узнаете, как разбить проект на независимые блоки, упростить поддержку и не сойти с ума.

Что такое модуль в Yii2 и зачем он нужен?

Модуль в Yii2 — это мини-приложение внутри основного приложения. У него есть свои контроллеры, модели, представления и конфигурация. Представьте, что вы собираете конструктор Lego. Каждый модуль — это отдельный блок. Вы можете его добавить, убрать или заменить, не ломая остальное.

Зачем это нужно? Допустим, у вас интернет-магазин. Есть каталог, корзина, админка, пользователи. Если всё свалить в одну кучу, через год вы проклянете день, когда начали проект. Модули решают эту проблему. Они изолируют функционал. Например, модуль "Каталог" отвечает только за товары. Модуль "Корзина" — за заказы. Они общаются через события или сервисы, но не лезут в код друг друга.

Ещё один плюс — переиспользование. Написали модуль для рассылки писем? Вставили его в другой проект — и готово. Экономия времени и нервов.

Правило: Модуль должен быть самодостаточным. Он может зависеть от других модулей только через интерфейсы или события. Никаких прямых вызовов методов из другого модуля. Иначе это уже не модуль, а спагетти.

Структура модуля: с чего начать?

Создание модуля начинается с папки. В Yii2 модули обычно лежат в modules/. Давайте создадим простой модуль для управления статьями блога.


// Структура папок:
modules/
    blog/
        controllers/
            DefaultController.php
        models/
            Article.php
        views/
            default/
                index.php
        Module.php
        config.php

Главный файл — Module.php. Он наследуется от yii\base\Module. В нём мы настраиваем пространство имён и подключаем конфигурацию.


<?php
namespace app\modules\blog;

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

    public function init()
    {
        parent::init();
        // Здесь можно загрузить конфиг
        $this->setAliases([
            '@blog' => __DIR__,
        ]);
    }
}

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


'modules' => [
    'blog' => [
        'class' => 'app\modules\blog\Module',
        // Можно передать свои параметры
        'params' => [
            'pageSize' => 20,
        ],
    ],
],

Всё. Теперь по адресу /blog/default/index будет доступен контроллер. Обратите внимание: URL строится как /moduleId/controllerId/actionId.

Контроллеры и модели внутри модуля

Контроллеры в модуле ничем не отличаются от обычных. Единственное — они должны быть в пространстве имён модуля. Давайте создадим контроллер для списка статей.


<?php
namespace app\modules\blog\controllers;

use yii\web\Controller;
use app\modules\blog\models\Article;

class DefaultController extends Controller
{
    public function actionIndex()
    {
        $articles = Article::find()->all();
        return $this->render('index', ['articles' => $articles]);
    }
}

Модели — тоже обычные. Только лежат в папке models модуля. Например, модель Article может работать с таблицей blog_articles. Чтобы не путаться, я рекомендую именовать таблицы с префиксом модуля.


<?php
namespace app\modules\blog\models;

use yii\db\ActiveRecord;

class Article extends ActiveRecord
{
    public static function tableName()
    {
        return 'blog_articles';
    }
}

Представления лежат в views/controllerId/. В нашем случае — views/default/index.php. Внутри можно использовать обычный HTML и PHP.


<h1>Список статей</h1>
<ul>
    <?php foreach ($articles as $article): ?>
        <li><?= Html::encode($article->title) ?></li>
    <?php endforeach; ?>
</ul>

Как модули общаются между собой?

Прямые вызовы методов из другого модуля — зло. Вместо этого используйте события или сервисный слой. Например, модуль "Корзина" хочет узнать цену товара из модуля "Каталог". Создайте интерфейс и реализуйте его в модуле.

Пример через события:


// В модуле catalog при сохранении товара
\Yii::$app->trigger('catalog.afterSave', new \yii\base\Event(['sender' => $this]));

// В модуле cart подписываемся
\Yii::$app->on('catalog.afterSave', function ($event) {
    // Обновить кэш корзины
});

Или через Dependency Injection. Создайте интерфейс PriceProviderInterface и зарегистрируйте его в контейнере.


// В конфиге приложения
\Yii::$container->set('app\interfaces\PriceProviderInterface', [
    'class' => 'app\modules\catalog\services\PriceProvider',
]);

// В модуле cart используем
$priceProvider = \Yii::$container->get('app\interfaces\PriceProviderInterface');
$price = $priceProvider->getPrice($productId);
Лайфхак: Используйте общий сервис-локатор для модулей. Создайте класс ModuleService, который предоставляет методы для работы с модулями. Это упростит тестирование и замену модулей.

Миграции и настройки модуля

Каждый модуль может иметь свои миграции. Создайте папку migrations внутри модуля. Затем в конфиге приложения укажите путь к миграциям модуля.


'controllerMap' => [
    'migrate' => [
        'class' => 'yii\console\controllers\MigrateController',
        'migrationPath' => [
            '@app/migrations',
            '@blog/migrations', // путь к миграциям модуля
        ],
    ],
],

Также модуль может иметь свои конфигурационные файлы. Например, config.php внутри модуля, который подгружается в init(). Это удобно для настройки правил URL или компонентов.

Параметр Описание Пример
controllerNamespace Пространство имён контроллеров app\modules\blog\controllers
defaultRoute Контроллер по умолчанию default
params Пользовательские параметры ['pageSize' => 20]

Что в итоге?

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

Главное — не пытайтесь сделать всё идеально сразу. Модульность должна расти естественно. Если чувствуете, что код начинает путаться — значит, пора делить на модули. Удачи в кодинге!

Студия WNDER