Yii2-advanced: альтернативное размещение папок для нескольких приложений

Хочу поделиться альтернативным рецептом файловой структуры для нескольких приложений в Yii2-advanced, не прибегая к модулям. Внешние отличия, к которым мы придем, выглядят следующим образом:

Конечная файловая архитектура


Вступление


Я видел на Хабре статью, как разные окружения превратить в модули и сложить их аккуратно внутри проекта. Мне кажется идея, которую мне показал коллега — намного круче и удобнее!

  • Идея такова, что мы не пишем в коде /site/site/index: мы пишем /site/index!
  • Мы не мучаемся с настройкой виртуальных хостов, сим-линков и реврайтов: мы все кидаем в один и тот же файл!
  • Мы можем иметь на бюджетном хостинге (теоретически) любое количество доменов, оплатив опцию «1 сайт»!

Разве это не круто?!

PS: Да, и кстати, к радости начинающих: вы можете решить проблему «как сделать общий upload для front&back».
PPS: Я рассчитываю, что вы уже установили и опробовали YII2 Advanced, и понимаете, зачем вам именно этот вариант.

Интересно? Тогда — вперед! Для примера беру последнюю, на текущий момент версию: 2.0.10.

Переходим к рефакторингу: первые шаги


  1. Если вы в предвкушении революции на работающем проекте, срочно жмем в папке своего проекта «tar -cf saveAndProtect.tar ./» Или выражаясь проще: предохраняемся, путем бекапа последней работающей версии. У меня чистая версия всего с одной вьюхой.

  2. Как видели на скриншоте выше: нужные нам приложения (applications) складываем в папку apps в корне проекта (да, ее нужно создать самому).

  3. В корне создаем папку web и перекидываем в нее содержимое своего фронт-энда (frontend). В папке backend удаляем папку web: теперь она общая. Лично мы тут храним лишь статику из картинок и шрифтов. Стили и JS так часто меняются, что лучше пользоваться ассетами (assets).

  4. Теперь перенастройте свои домены на новую папку web, в корне проекта, и приступаем к более сложным манипуляциям.

Шаг второй: немного доработать напильником (с)


  1. Правим первые три инклуда (include) в index.php, где подключается autoload, Yii и common/ bootstrap: просто убрать один уровень соответственно. Последний инклуд мы подключить пока не можем, т.к. это уже bootstrap, который относится к конкретному приложению из папки apps.

  2. Различать приложения, для старта будем банально: $_SERVER['HTTP_HOST']. Пишем switch-case и заменяем этим кодом последний инклуд и на этом с index.php мы закончили. Должно получится так:

    // определяем запрошенный APP
    switch ($_SERVER['HTTP_HOST']) {
    	case 'frontend.dev':
    	case 'site.ru':
    		define('YII_APP', 'frontend');
    		break;
    	case 'backend.dev':
    	case 'admin.site.ru':
    		define('YII_APP', 'backend');
    		break;
    	default:
    		// лично у меня тут 301й редирект на главную
    		exit("domain not defined");
    }
    
    // определяем папку приложения и подключаем его конфиг
    define('YII_APP_DIR', Yii::getAlias('@apps') . '/' . YII_APP);
    require(YII_APP_DIR . '/config/bootstrap.php');
    

  3. Могли обратить внимание, что добавился новый алиас(alias) @apps: это как раз наша новая папка. А константа YII_APP — конкретное приложение-папка, что необходимо подключить. Все прозрачно! Выглядит — ну да, соглашусь: может слегка «топористо». Но именно то, что нужно для быстрого старта.

  4. В мерже (merge) конфига у нас остались старые пути. В одном случае понижаем инклуд на уровень, во втором — используем нашу новую константу:

    $config = yii\helpers\ArrayHelper::merge(
    	require(__DIR__ . '/../common/config/main.php'),
    	require(__DIR__ . '/../common/config/main-local.php'),
    	require(YII_APP_DIR . '/config/main.php'),
    	require(YII_APP_DIR . '/config/main-local.php')
    );
    

  5. Теперь пора определить алиас @apps и поправить наши имеющиеся. Это правится в третьем подключаемом файле: common\config\bootstrap.php

    Добавляем алиас: Yii::setAlias('@apps', dirname(dirname(__DIR__)). '/apps');
    Наши приложения правим по принципу: Yii::setAlias('@console', Yii::getAlias('@apps'). '/console');.

  6. И последнее: осталось настроить нашу console. Вы можете это сделать сами, из спортивного интереса. А можете открыть спойлер и получить готовое решение:

    Настройка консольной части Yii2
    ./yii.php
    #!/usr/bin/env php
    <?php
    
    defined('YII_DEBUG') or define('YII_DEBUG', true);
    defined('YII_ENV') or define('YII_ENV', 'dev');
    define('YII_APP', 'console');
    
    require(__DIR__ . '/vendor/autoload.php');
    require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
    require(__DIR__ . '/common/config/bootstrap.php');
    require(__DIR__ . '/apps/console/config/bootstrap.php');
    
    $config = yii\helpers\ArrayHelper::merge(
        require(__DIR__ . '/common/config/main.php'),
        require(__DIR__ . '/common/config/main-local.php'),
        require(__DIR__ . '/apps/console/config/main.php'),
        require(__DIR__ . '/apps/console/config/main-local.php')
    );
    
    $application = new yii\console\Application($config);
    $exitCode = $application->run();
    exit($exitCode);
    

    apps\console\config\main.php правим участок с merge
    $params = array_merge(
        require(__DIR__ . '/../../../common/config/params.php'),
        require(__DIR__ . '/../../../common/config/params-local.php'),
        require(__DIR__ . '/params.php'),
        require(__DIR__ . '/params-local.php')
    );
    


Все!

Работающий сайт после смены архитектуры


Работающая консоль после смены архитектуры


Резюме


Довольно простыми манипуляциями для человека немного поработавшего с YII2 мы получили структурированный по приложениям проект, который откликается на любое количество доменов и удобен на бюджетных хостингах, когда у нас есть лишь 1 каталог. Либо манипуляции с каталогами и сим-линками вызывает определенные проблемы.

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

В: У меня, на шаге Х просто белый экран!
О: Вы допустили опечатку до инициализации Yii. Временно добавьте в самое начало index.php строку: ini_set(«display_errors»,«1»); ini_set(«error_reporting», E_ALL);

В: Скомпиленные Ассеты могут смешаться?
О: Вряд ли. Почти за год работы проекта не отмечено ни одного случая

В: Robots и favico не для каждого домена, а смешаны в кучу?
О: Всегда можно разрулить реврайтами апача по RewriteCond %{HTTP_HOST}

В: А как можно получить ссылку из другого приложения? На примере «модулей», это было бы элементарно.
О: Создайте дополнительную компоненту и Yii::$app->urlManagerFrontend->createUrl(...);
Поделиться публикацией

Комментарии 14

    +1
    Не надо изобретать велосипед, и учить этому других.

    Если вам нужны несколько сайтов, зависимых друг от друга (допустим, admin.example.com, crm.example.com, mail.example.com, etc), то делаете каждый подсайт в виде модуля и указываете роутинг с нужного домена в конфиге (см. http://nickbartlett.com/yii-multisite-point-domain-to-modules/ ). При этом, webroot с каждого домена идет на одну и ту же папку.

    Если же сайты не должны быть зависимы друг от друга, то вообще в разные проекты нужно разделять всё.
      +1
      Вы совершенно верно мыслите, с точки зрения человека, которому доступен личный сервер.
      Но, находясь на урезанном хостинге и с желанием экономии — будет слегка напряжно реализовать все красиво.
      На счет модулей — я сразу оговорил, что предлагаю вариант без оных. Также есть отзыв пришедшего программиста в нашу команду, который сказал: «О, так понятнее и проще, чем на модулях»
      А сайты… В нашем случае это можно сравнить с фрилансом. Когда есть сторона работодателя и соискателя. У которых пересекаются модели, методы, данные, компоненты и т.д.

      Велосипед буду изобретать, т.к. только так делаются какие-то прорывы из консерватизма.
      Чтоб учить, необходимо сказать: «делайте так». Я лишь предложил альтернативу, которую внедрили в моем проекте, и которая лично мне приглянулась.
      Девяти добавлениям в избранное, видимо, также.

      Спасибо за отзыв. Я не претендую на прорыв в технологиях. Буду рад, если кому данный подход также понравится больше, чем модульность или у кого нет желания вкладываться в хостинг.
      0
      чем плох этот вариант https://github.com/mickgeek/yii2-advanced-one-domain-config?
        0
        Если вы имели в виду, «как мне это решение», то если я верно понял — то интересное решение. Более быстрая настройка и неизменная структура файлов
        Из плюсов моего варианта — более удобно, если, ни дай бог, два или более приложений должны иметь общие ресурсы: картинки, шрифты.

        Я выше отметил, что у нас сильно было завязано на 2 приложения. У них было много общего. Т.е. как предлагали — можно было сделать через модули. Попробовали сделать так — лично нам понравилось. Штатный вариант теперь чет не нравится)
        0
        Это только Yii под backend и frontend понимает админку и часть для обычных пользователей соответственно?
        Или это общепринято? :)

        Я чет всю жизнь под первым понимал сервер-сайд, под вторым — отдача html + статики. :)

        С учетом общих файлов статики, данное решение более удобно применять для поддоменов. :)
        Хотя можно статику разнести по папкам доменов, а php натравить на:
        а) общий файл;
        б) разные файлы, но иметь предложенную структуру папок.
          0
          Ну второй идет в двух вариантах: advanced с такой структурой и basic. Там по другому

          А текущее решение — не обязательно применять))) Его еще можно перекроить 10 раз. Мне, до написания этой статьи, просто было немного не понятно как этот Yii «склеивается». Попутно разобрался и избавился от мандража, что перекроить Yii — это страшно)
            0

            Тут стоит понимать что yii2-app-advanced и yii2-app-basic — это не окончательные варианты структуры проектов. Это шаблоны от команды фреймворка, как можно организовать структуру на одну и на несколько точек входа. Кому подходит, тот пользуется готовым. Кому нет — делает свой шаблон.


            Вы даже можете оформить свой вариант в виде пакета для composer, чтобы начинать новые проекты по этому шаблону с команды:


            composer create-project --prefer-dist username/yii2-app-cool .
            0
            Термины «backend» и «frontend» имеют значение в зависимости от контекста. Это может быть админка/сайт, сервер/браузер, apache/nginx и т.д. Это просто обозначение 2 сторон канала передачи информации.
              0
              Это только Yii под backend и frontend понимает админку и часть для обычных пользователей соответственно?
              Или это общепринято? :)

              Это очень давно было так принято, во времена, когда на JS не писали приложения, и отдельно JS-разработчики не нанимались.
              Бэкендом называлась админка, фронтендом — пользовательская часть.
              0
              Интересное решение. Попробуйте на github опубликовать ;)
              Лично я склоняюсь больше к использованию Yii-basic и модульности. Поскольку кажется, что yii advanced склоняет мешать логику в разных частях приложения, делая проект тем самым более запутанным. Лучше делать несколько проектов со своими направлениями, чем один с разными приложениями.
                0
                Интересное решение. Попробуйте на github опубликовать ;)

                Спасибо. Да там выше предложена ссылка, где эта задача решается на уровне одного только веб-сервера с помощью реврайтов. Можно сказать, что моя «миссия» уже выполнена другим человеком))))
                0
                Если подходит вариант с поддиректорией («mysite.com/» и «mysite.com/admin»), то тут есть хорошее решение. Переносим папку «backend/web» в «frontend/web/admin» и корректируем пути в «admin/index.php».
                  +1
                  Следует понимать, что Yii2 можно законфигурировать почти произвольным образом. Есть понятие входного скрипта, которые подключает нужные конфиги из папочек. Соответственно, перенастроив этот входной скрипт можно организовать себе произвольную структуру проекта. Но всё-же смешивать разные проекты в одном — это bad design, и оправдывать это только хостингом, при условии того, что найти недорогой VPS очень даже легко.
                    +1
                    Как жаль, что есть люди, знающие про Yii2 и не знающие про display_errors

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

                    Самое читаемое