Порядок загрузки модулей и классов в Koseven (Kohana)

Ключевой принцип Koseven: "Кто ниже в списке — тот важнее". Модули, объявленные позже, имеют более высокий приоритет и могут переопределять классы, конфиги и представления модулей, указанных ранее.

1. Каскадная файловая система (Cascading Filesystem)

Koseven использует каскадный поиск файлов. Когда фреймворку нужно найти класс, конфигурацию или представление, он проверяет пути в строгом порядке:

1. APPPATH

application/ — наивысший приоритет. Все, что лежит здесь, перекрывает всё остальное.

2. MODPATH (снизу вверх)

Модули из Kohana::modules(). Поиск идет с последнего к первому в списке.

3. SYSPATH

system/ — наинизший приоритет. Используется, если ничего не нашли выше.

2. Как происходит поиск класса? (на примере User)

При вызове класса User автозагрузчик ищет файл classes/User.php в следующем порядке:

Порядок Путь Приоритет
1 (самый высокий) application/classes/User.php Всегда первый
2 application/modules/erp218_module_manager/classes/User.php Если модуль последний в списке
3 modules/auth/classes/User.php Если модуль первый в списке
4 (самый низкий) system/classes/User.php Всегда последний

❗ Важно: Как только файл найден, он сразу подключается через require и поиск прекращается. Остальные файлы с таким же именем игнорируются. PHP не умеет "склеивать" части одного класса из разных файлов.

3. Как правильно "дополнить" класс (Transparent Extension)

Чтобы добавить функциональность без копирования всего класса, используйте наследование:

// system/classes/Kohana/User.php (оригинал)
class Kohana_User {
    public function login() { /* ... */ }
}

// application/classes/User.php (ваше расширение)
class User extends Kohana_User {
    // Ваши новые методы
    public function login_with_2fa() { /* ... */ }
    
    // Можно переопределить существующие
    public function login() {
        // Дополнительная логика
        parent::login();
    }
}

Теперь User будет иметь все методы из Kohana_User плюс ваши.

4. Правильный порядок модулей в Kohana::modules()

Располагайте модули от общих/инфраструктурных к частным/специфичным:

Kohana::modules(array(
    // 1. Системные (фундамент)
    'database' => MODPATH.'database',
    'orm'      => MODPATH.'orm',
    'cache'    => MODPATH.'cache',
    
    // 2. Базовые сервисы (библиотеки)
    'auth'     => MODPATH.'auth',
    'llm'      => APPPATH.'modules/llm', // ← Базовый модуль, который используют другие
    
    // 3. Ядро приложения
    'entity'   => APPPATH.'modules/entity',
    'erp100_core' => APPPATH.'modules/erp100_core',
    
    // 4. Функциональные модули (зависят от вышеперечисленных)
    'erp118_links' => APPPATH.'modules/erp118_links',
    'erp210_crm'   => APPPATH.'modules/erp210_crm',
    
    // 5. Специализированные/вспомогательные
    'erp217_notification_center' => APPPATH.'modules/erp217_notification_center',
    'erp218_module_manager'      => APPPATH.'modules/erp218_module_manager',
));

✅ Правило: Если модуль A использует модуль B, то B должен стоять выше A в списке. Тогда A сможет использовать классы B, а при необходимости переопределить их — просто поместит свои файлы в свою папку.

5. Часто задаваемые вопросы

Q: Если класс есть и в application/classes/, и в модуле, что загрузится?

A: application/classes/ всегда имеет наивысший приоритет. Файл из модуля будет проигнорирован.

Q: Можно ли "дополнить" класс из модуля, не меняя его код?

A: Да, через наследование. Создайте в своем модуле (который ниже в списке) класс с тем же именем, но унаследованный от оригинального. Например, для Model_User из модуля auth создайте в своем модуле class Model_User extends Model_Auth_User.

Q: Что если два модуля внизу списка имеют одинаковые классы?

A: Приоритет у того, кто ниже (объявлен позже). Например, если erp218_module_manager и erp210_crm оба имеют classes/Helper.php, загрузится файл из erp218_module_manager, так как он стоит ниже.

Совет: При разработке модулей всегда учитывайте их зависимости. Сначала идут "строительные блоки" (база данных, ORM, авторизация), затем "бизнес-логика" (CRM, склад). Это обеспечит гибкость и возможность переопределения поведения на уровне приложения.