Multisite Set up with shared views, controllers and models Phalcon

 

Multiple site setup in phalcon steps

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.

 

I need to setup multisite in phalcon where I need some common functionalities to be done among all sites and also will have site specific. Say it would have some common controllers modals and views, if I need anything to be changed in one particular site I should be able to change in that particular site with out affecting other sites. just by creating single view template and extending the controllers and modals. If i need to change anything in all sites then I could be able to change it in a single place.

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

  • * Step 1 : Register the namespaces of common controllers and models
  • * Step 2 : Extend the phalcon view engine to cascading the view (say for example View engine will  look for specific template file in site specific view folder if its not exist it will look in common  views folder, there is no need to replicate all the template files in all sites views directories, you can overwrite single template file alone).
  • * Step 3 : Extend  Phalcon volt to provide Skin path for tempaltes
  • * Step 4:  Create site specfic Volt cache folder
  • * Step 5 :  Create seperate folders with sitenames in public folder for  js/css/images
  • * Step 6:  Create common contollers, views, modals
  • * Step 7:  Extend common controllers , modals in site specific folderss , Views wil be taken from common  folder. if you  want to overwrite any template you can overwiite that alone no need all view folder.
  • * Step 8 : Set sitename by current domain name. this sitename will be used to register contollers models directries
  • * Step 9:  Set two views  directory one is common and another is sitename (thi can be done only if you have extened the phalcon view to add two directories refer step 2)

 

Files extended are here, this should be in your root 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

 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;
               }
            }
        }
}

public/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') }}

Git hub : https://github.com/karthikeyan-unimity/phalcon

Phalcon Forum : https://forum.phalconphp.com/discussion/12677/multisite-set-up-with-shared-views-controllers-and-models

 

multi site