[Из песочницы] 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
    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 (…);

Комментарии (12)

  • 6 декабря 2016 в 18:00 (комментарий был изменён)

    0

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

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

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

    • 6 декабря 2016 в 18:11

      0

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

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

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

  • 6 декабря 2016 в 21:42

    0

    чем плох этот вариант https://github.com/mickgeek/yii2-advanced-one-domain-config?
    • 6 декабря 2016 в 21:58

      0

      Если вы имели в виду, «как мне это решение», то если я верно понял — то интересное решение. Более быстрая настройка и неизменная структура файлов
      Из плюсов моего варианта — более удобно, если, ни дай бог, два или более приложений должны иметь общие ресурсы: картинки, шрифты.

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

  • 6 декабря 2016 в 21:59

    0

    Это только Yii под backend и frontend понимает админку и часть для обычных пользователей соответственно?
    Или это общепринято? :)

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

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

    • 6 декабря 2016 в 22:07

      0

      Ну второй идет в двух вариантах: advanced с такой структурой и basic. Там по другому

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

      • 6 декабря 2016 в 22:38

        0

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


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


        composer create-project --prefer-dist username/yii2-app-cool .
    • 7 декабря 2016 в 07:07

      0

      Термины «backend» и «frontend» имеют значение в зависимости от контекста. Это может быть админка/сайт, сервер/браузер, apache/nginx и т.д. Это просто обозначение 2 сторон канала передачи информации.
    • 7 декабря 2016 в 08:58

      0

      Это только Yii под backend и frontend понимает админку и часть для обычных пользователей соответственно?
      Или это общепринято? :)

      Это очень давно было так принято, во времена, когда на JS не писали приложения, и отдельно JS-разработчики не нанимались.
      Бэкендом называлась админка, фронтендом — пользовательская часть.
  • 7 декабря 2016 в 08:35

    0

    Интересное решение. Попробуйте на github опубликовать ;)
    Лично я склоняюсь больше к использованию Yii-basic и модульности. Поскольку кажется, что yii advanced склоняет мешать логику в разных частях приложения, делая проект тем самым более запутанным. Лучше делать несколько проектов со своими направлениями, чем один с разными приложениями.
    • 7 декабря 2016 в 08:39 (комментарий был изменён)

      0

      Интересное решение. Попробуйте на github опубликовать ;)

      Спасибо. Да там выше предложена ссылка, где эта задача решается на уровне одного только веб-сервера с помощью реврайтов. Можно сказать, что моя «миссия» уже выполнена другим человеком))))
  • 7 декабря 2016 в 09:26

    0

    Если подходит вариант с поддиректорией («mysite.com/» и «mysite.com/admin»), то тут есть хорошее решение. Переносим папку «backend/web» в «frontend/web/admin» и корректируем пути в «admin/index.php».

© Habrahabr.ru