We had a situation where we need to setup multi site with shared views , templates , controllers, models with site specific templates ,controllers and models too.
|
Jan '17 |
4 |
1602 |
0 |
https://monkpal.com/Multisite-Set-up-with-shared-views-controllers-and-modals-Phalcon
multisite/shared
├── apps
│ ├── common
│ │ ├── controllers (Register namespace Common/Controller)
│ │ │ ├── IndexController.php
│ │ │ ├── LoginController.php
│ │ │ └── ProductsController.php
│ │ ├── models (Register namespace Common/Model)
│ │ │ └── Products.php
│ │ └── views
│ │ ├── login
│ │ │ └── index.volt
│ │ └── products
│ │ | └── index.volt
| | └──index.volt
│ ├── example.com
│ │ ├── controllers
│ │ │ ├── IndexController.php (extend Common/Controller)
│ │ │ ├── LoginController.php (extend Common/Controller)
│ │ │ ├── ProductsController.php (extend Common/Controller)
│ │ │ └── UsersController.php Site Specific Controller
│ │ ├── models
│ │ │ └── Products.php (extend Common/Model)
| | | └── Users.php (Site Specific Model)
│ │ └── views
│ │ └── products (Other view templates will refer to Common view folder)
│ │ └── index.volt
│ ├── example2.com
│ │ ├── controllers
│ │ │ ├── IndexController.php (extend Common/Controller)
│ │ │ ├── ProductsController.php (extend Common/Controller)
│ │ │ └── SitespecificController.php Site Specific Controller
│ │ ├── models
│ │ │ └── Products.php (extend Common/Model)
| | | └── SiteSpecific.php (Site Specific Model)
│ │ └── views
│ │ └── sitespecific (Other view templates will refer to Common view folder)
│ │ └── index.volt
└── public
└── example.com (Will contain Js CS Images to support site specific theme)
└── example2.com (Will contain Js CS Images to support site specific theme)
└── index.php
Steps to setup multiple site with different domain name
Steps to acheive it
Files extended are here this should be in your public directory.
custom/CustomVolt.php
<?php namespace Custom; use Phalcon\Mvc\View\Engine\Volt; use Phalcon\Mvc\View\Engine\Volt\Compiler; class CustomVolt extends Volt { public function getCompiler() { if (!$this->_compiler) { $this->_compiler = new VoltCompilerExtension($this->getView()); $this->_compiler->setOptions($this->getOptions()); $this->_compiler->setDI($this->getDI()); } return $this->_compiler; } } class VoltCompilerExtension extends Volt\Compiler { public function compileFile($path, $compiledPath, $extendsMode = null) { $skinPath = $this->getOption('skinPath'); if ($skinPath) { $skinTemplate = str_replace( $this->getDI()->getView()->getViewsDir(), $skinPath, $path ); if (is_readable($skinTemplate)) { $path = $skinTemplate; } } return parent::compileFile($path, $compiledPath, $extendsMode); } }
custom/CustomView.php
<?php namespace Custom; use Phalcon\Mvc\View\Exception; use Phalcon\Mvc\View; use Phalcon\Cache\BackendInterface; class CustomView extends View { protected $_viewsDirs; /** * @var */ protected $_eventsManager; /** * @param $path * * @return $this */ public function addViewsDir($path) { $this->_viewsDirs = $path; $this->setViewsDir($path); return $this; } /** * @param $view * @param array $vars * * @return string */ public function getPartial($view, $vars = []) { ob_start(); $this->partial($view, $vars); $content = ob_get_contents(); ob_end_clean(); return $content; } protected function _engineRender($engines, $viewPath, $silence, $mustClean, BackendInterface $cache = NULL) { if (is_object($cache)) { throw new Exception('Cache view not supported...'); return; } $viewsDirs = is_array($this->_viewsDirs) ? array_reverse($this->_viewsDirs) : [$this->_viewsDir]; $notExists = true; $viewEnginePath = null; foreach ($engines as $extension => $engine) { foreach ($viewsDirs as $viewsDir) { $viewsDirPath = $this->_basePath . $viewsDir . $viewPath; $viewEnginePath = $viewsDirPath . $extension; if (is_file($viewEnginePath)) { if (is_object($this->_eventsManager)) { $this->_activeRenderPath = $viewEnginePath; if($this->_eventsManager->fire('view:beforeRenderView', $this, $viewEnginePath) === false) { break; } } $engine->render($viewEnginePath, $this->_viewParams, $mustClean); if (is_object($this->_eventsManager)) { $this->_eventsManager->fire('view:afterRenderView', $this); } $notExists = false; break 2; } } } if ($notExists) { if (is_object($this->_eventsManager)) { $this->_activeRenderPath = $viewEnginePath; $this->_eventsManager->fire('view:notFoundView', $this); } if (!$silence) { $exceptionMessage = 'View "'.($viewPath).'" was not found in the views directories'; throw new Exception($exceptionMessage); return; } } } }
index.php
<?php
use Phalcon\Loader; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; use Phalcon\Mvc\Url as UrlProvider; use Custom\CustomVolt; use Custom\CustomView; if($_SERVER['HTTP_HOST'] == "example.com") { define('SITENAME',"example.com" ); } if($_SERVER['HTTP_HOST'] == "example2.com") { define('SITENAME',"example2.com" ); } define('APP_PATH', realpath('..') . '/');
try {
$loader = new Loader(); $loader->registerNamespaces(array( 'Common\Controller' => '../app/common/controllers', 'Common\Model' => '../app/common/models', 'Custom' => 'custom' ))->register(); $loader->registerDirs(array( '../app/'.SITENAME.'/controllers/', '../app/'.SITENAME.'/models/' ))->register(); $di = new FactoryDefault(); $di->set( 'voltService', function ($view, $di) { $volt = new CustomVolt($view, $di); $volt->setOptions( array( "compiledPath" => "../cache/volt/".SITENAME."/", "compiledExtension" => ".compiled", 'compileAlways' => true, 'skinPath' => '../app/'.SITENAME.'/views/' ) ); return $volt; } ); $di->set( 'view', function () { $view = new CustomView(); $view->addViewsDir(array('../app/common/views/','../app/'.SITENAME.'/views/')); $view->registerEngines( array( ".volt" => 'voltService' ) ); return $view; } ); $application = new Application($di); $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo "Exception: ", $e->getMessage(); }
To render Js and css site specific in volt tempaltes
You use can like this
{{ stylesheet_link(constant('SITENAME') ~'/css/main.css') }}
{{ javascript_include(constant('SITENAME') ~'/js/main.js') }}
skeleton in github https://github.com/karthikeyan-unimity/phalcon
something complicated.
Drupal approach: https://www.drupal.org/docs/7/multisite-drupal/multi-site-sharing-the-same-code-base
in Phalcon my recomendation:
- app
- default
- config
- config.php
- loader.php
- services.php
- lang
- other_site
sites.php
- core
- web
index.php
site.php
<?php
$sites['u-w-u.local'] = 'default';
index.php
<?php
use Phalcon\Di;
use Phalcon\Mvc\Micro;
error_reporting(E_ALL);
define('APP_PATH', realpath('..'));
define('WEB_PATH', realpath('.'));
/**
* Enable multisite
*/
$sites = [];
include '../app/sites.php';
$siteDomain = $_SERVER['SERVER_NAME'];
if (isset($sites[$siteDomain]) && file_exists(APP_PATH . '/app/' . $sites[$siteDomain] . '/config/config.php')) {
$sitePath = APP_PATH . '/app/' . $sites[$siteDomain];
try {
$di = new Di();
/**
* Include Services
*/
include $sitePath . '/config/services.php';
require '../autoload.php';
/**
* Call the autoloader service. We don't need to keep the results.
*/
$di->getLoader();
/**
* Starting the application
* Assign service locator to the application
*/
$app = new Micro($di);
/**
* Debug
*/
if ($app->config->dev_environment) {
Kint::$theme = 'solarized';
$debug = new \Phalcon\Debug();
$debug->listen();
}
/**
* Include Application
*/
foreach ($app->config->modules as $module => $config) {
if ($config['active'] == true) {
include APP_PATH . '/core/modules/' . $module . '/' . $module . '.routing.php';
if ($config['api'] == true) {
include APP_PATH . '/core/modules/' . $module . '/' . $module . '.routing.api.php';
}
}
}
/**
* Handle the request
*/
$app->handle();
} catch (\Exception $e) {
echo $e->getMessage() . '<br>';
echo '<pre>' . $e->getTraceAsString() . '</pre>';
}
} else {
// TODO: Mejorar el mensaje de site no encontrado
echo "Index.php: Acceso no permitido.";
}
hopefully help you.
Hi all. I've worked around https://monkpal.com/Multisite-Set-up-with-shared-views-controllers-and-modals-Phalcon doing some change.
I have a new directory for templates in the root
templates
├── frontend
│ ├── common
│ │ ├── layouts
│ │ │ ├── index.volt
│ │ │ ├── cart.volt
| │ | └── ... etc etc
│ │ │
│ │ ├── views
│ │ │
│ │ └── partials
│ │ │
│ │ └── layouts.volt │ │
│ ├── sitename1
│ │ ├── layouts
│ │ │ ├── index.volt
│ │ │ ├── cart.volt
| │ | └── ... etc etc
│ │ │
│ │ ├── views
│ │ │
│ │ └── partials │ │ │
│ │ └── layouts.volt │ ├── sitename2
│ │ ├── layouts
│ │ │ ├── index.volt
│ │ │ ├── cart.volt
| │ | └── ... etc etc
│ │ │
│ │ ├── views
│ │ │
│ │ └── partials
│ │ │
│ │ └── layouts.volt
there is a common directory for default templates and a directory for every site. Sitename files , if exist, override common. In every dir there is a file layouts.volt for the general template. In layouts subdir there are the general controller templates. In views subdir there are the action templates. In partials subdir there are the partials templates.
The view service init is:
<?php
$di->setShared(
'view',
function () {
$conf=$this->get('config');
$mainView='layout';
$engines = array(
".volt" => 'voltService',
".phtml" => "Phalcon\Mvc\View\Engine\Php"
);
$view = new \Extended\ExtendedView();
$view->addViewsDir(array(TEMPLATE_PATH.'frontend/common/'.$conf->application->viewsDir, TEMPLATE_PATH.'frontend/'.SITENAME.'/'.$conf->application->viewsDir));
$view->addTemplatesDir(array(TEMPLATE_PATH.'frontend/common/', TEMPLATE_PATH.'frontend/'.SITENAME.'/'));
// Set the engine
$view->registerEngines($engines);
$view->setMainView($view->getRightPath($mainView,$engines).$mainView); //main layout
return $view;
}
);
The ExtendedView class modified in order to manage partials and other templates override.
<?php
namespace Extended;
use Phalcon\Mvc\View\Exception;
use Phalcon\Mvc\View;
use Phalcon\Cache\BackendInterface;
class ExtendedView extends View
{
protected $_viewsDirs, $_templatesDirs;
/**
* @var
*/
protected $_eventsManager;
/**
* @param $path
*
* @return $this
*/
public function addViewsDir($path)
{
$this->_viewsDirs = $path;
//$this->setViewsDir($path);
return $this;
}
public function addTemplatesDir($path)
{
$this->_templatesDirs = $path;
//$this->setViewsDir($path);
return $this;
}
public function getRightPath($viewPath, $engines = [])
{
$templatesDirs = is_array($this->_templatesDirs) ? array_reverse($this->_templatesDirs) : [$this->_templatesDirs];
if(empty($engines)) $engines = $this->_loadTemplateEngines();
foreach ($engines as $extension => $engine) {
foreach ($templatesDirs as $viewsDir) {
$viewsDirPath = $this->_basePath . $viewsDir . $viewPath; //directory completa con nome della vista finale
$viewEnginePath = $viewsDirPath . $extension; //path completo del file con estensione es .volt .phtml
if (is_file($viewEnginePath)) {
if($viewsDir) return $viewsDir; //imposta la dir della view
}
}
}
return null;
}
/**
* @param $path
*
* @return $this
public function addPartialsDir($path)
{
$this->_partialsDirs = $path;
$this->setPartialsDir($path);
return $this;
}
*/
/**
* @param $view
* @param array $vars
*
* @return string
*/
public function getPartial($view, $vars = [])
{
ob_start();
$this->partial($view, $vars);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
protected function _engineRender($engines, $viewPath, $silence, $mustClean, BackendInterface $cache = null){
//$silence=false;
//echo "($engines, $viewPath, $silence, $mustClean, BackendInterface $cache = null)";
/* */
$viewsDirs = is_array($this->_viewsDirs) ? array_reverse($this->_viewsDirs) : [$this->_viewsDir];
$notExists = true; //?
$viewEnginePath = null;
foreach ($engines as $extension => $engine) {
foreach ($viewsDirs as $viewsDir) {
$viewsDirPath = $this->_basePath . $viewsDir . $viewPath; //directory completa con nome della vista finale
$viewEnginePath = $viewsDirPath . $extension; //path completo del file con estensione es .volt .phtml
if (is_file($viewEnginePath)) {
if($viewsDir) $this->setViewsDir($viewsDir); //imposta la dir della view
return parent::_engineRender($engines, $viewPath, $silence, $mustClean, $cache);
}
}
}
return parent::_engineRender($engines, $viewPath, $silence, $mustClean, $cache);
}
public function render($controllerName, $actionName, $vars = []){
/**
* Check if there is a layouts directory set
*/
$layoutsDir = $this->_layoutsDir;
if (!$layoutsDir) {
$layoutsDir = "layouts/";
}
/**
* Check if the user has defined a custom layout
*/
$layout = $this->_layout;
if ($layout) {
$layoutName = $layout;
} else {
$layoutName = $controllerName;
}
$this->_layoutsDir=$this->getRightPath($layoutsDir.$layoutName).$layoutsDir;
return parent::render($controllerName, $actionName, $vars);
}
public function partial($partialPath, $vars = [])
{
if(!$this->_partialsDir) $this->_partialsDir='partials/';
$this->_partialsDir=$this->getRightPath($this->_partialsDir.$partialPath).$this->_partialsDir;
return parent::partial($partialPath, $vars);
}
}
I think it's more complete and usable by web designers now. In my project I use modules in order to separate backend and frontend, mantaining the multisite only in the frontend module only.