Override CWebApplication or not override? That's where a question.

Hi, my application has several ends:

  • "front" end

  • "robot" end

  • "panel/manager" end

  • "panel/centr" end

  • "panel/provider" end

the implementation of several ends in one application is like this one http://www.yiiframework.com/wiki/63/

But, it has one problem. Controller class names in each end can be the same.

For example, I can open protected/controller/front/TaskController (which extends BaseTaskController, which extends Controller, which extends CController) from front-end and do something from front-end.

And I can also open another protected/controller/panel/manager/TaskController from manager panel, and do something.

Classes with same names in one project is very bad.

I want end-controllers to have different names, like "TaskFrontController", "TaskManagerController".

I tried to do this in different ways, including changing urlManager rules.

Finaly i came up with idea that the only good implementation, is to change strings of CWebApplication->createController

from




			$className=ucfirst($id).'Controller';

			$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php';

to




         			$className=$this->getControllerClassName($id);

         			$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php'; 

where getControllerClassName is





    /*

     * Controller name by id, => IdEndnameController

     */

    public function getControllerClassName($id){

        return(ucfirst($id).$this->_endControllerPostfix.'Controller');

    }



but i can’t find the way to do it, without creating new core class “CWebEndApplication”, extending CWebApplication and overriding createController method.

Is it the only way to do that?

finaly I made CWebEndApplication:


<?php

/**

 * CWebEndApplication class file.

 *

 * @author Max Zhuravlev

 */


/*

 * Расширяет CWebApplication поведением "End".

 * Если в конфиге задать endName, например shop или panel/manager, то:

 *

 * Controller "task" будет искаться в controllerPath/shop/TaskShopController.php или соответственно в controllerPath/panel/manager/TaskManagerController.php

 * View будет искаться в viewPath/shop/view.php или соответственно в viewPath/panel/manager/view.php

 *

 * Благодаря этому:

 *  - контроллеры и view лежат по своим папкам в соответствии с "концами" приложения.

 *  - не пересекаются.

 *

 */


class CWebEndApplication extends CWebApplication

{

    /*

     * Web application end's name.

     *  for example:

     *  shop

     *  panel/centr

     */

    public $endName="";


    private $_endControllerPostfix=null;


	private $_controllerPath;

	private $_viewPath;

	private $_systemViewPath;

	private $_layoutPath;

	private $_controller;

	private $_theme;




    /*

     * @return End controller postfix, based on endName

     * "" => ""

     * shop => Shop

     * panel/centr => Centr

     *

     */

    public function getEndControllerPostfix(){

        if(is_null($this->_endControllerPostfix)){

            $this->_endControllerPostfix=ucfirst(strtolower(array_pop(explode('/',$this->endName))));

        }

        return($this->_endControllerPostfix);

    }


	/*

     *  @desc Полностью идентичен методу из CWebApplication кроме строчки c $this->getEndControllerPostfix()

	 */

	public function createController($route,$owner=null)

	{

		if($owner===null)

			$owner=$this;

		if(($route=trim($route,'/'))==='')

			$route=$owner->defaultController;

		$caseSensitive=$this->getUrlManager()->caseSensitive;


		$route.='/';

		while(($pos=strpos($route,'/'))!==false)

		{

			$id=substr($route,0,$pos);

			if(!preg_match('/^\w+$/',$id))

				return null;

			if(!$caseSensitive)

				$id=strtolower($id);

			$route=(string)substr($route,$pos+1);

			if(!isset($basePath))  // first segment

			{

				if(isset($owner->controllerMap[$id]))

				{

					return array(

						Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner),

						$this->parseActionParams($route),

					);

				}


				if(($module=$owner->getModule($id))!==null)

					return $this->createController($route,$module);


				$basePath=$owner->getControllerPath();

				$controllerID='';

			}

			else

				$controllerID.='/';

			$className=ucfirst($id).$this->getEndControllerPostfix().'Controller';

			$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php';

			if(is_file($classFile))

			{

				if(!class_exists($className,false))

					require($classFile);

				if(class_exists($className,false) && is_subclass_of($className,'CController'))

				{

					$id[0]=strtolower($id[0]);

					return array(

						new $className($controllerID.$id,$owner===$this?null:$owner),

						$this->parseActionParams($route),

					);

				}

				return null;

			}

			$controllerID.=$id;

			$basePath.=DIRECTORY_SEPARATOR.$id;

		}

	}


	/**

     * @desc Идентичен методу из CWebApplication, но добавляет в конец "$this->endName"

	 * @return string the directory that contains the controller classes. Defaults to 'protected/controllers/endName'.

	 */

	public function getControllerPath()

	{

        if(is_null($this->_controllerPath)){

            $this->_controllerPath=$this->getBasePath().DIRECTORY_SEPARATOR.'controllers';

        }

        return $this->_controllerPath.DIRECTORY_SEPARATOR.$this->endName;

	}


	/**

     * @desc Идентичен методу из CWebApplication, но добавляет в конец "$this->endName"

	 * @return string the root directory of view files. Defaults to 'protected/views/endName'.

	 */

	public function getViewPath()

	{

        if(is_null($this->_viewPath)){

            $this->_viewPath=$this->getBasePath().DIRECTORY_SEPARATOR.'views';

        }

        return $this->_viewPath.DIRECTORY_SEPARATOR.$this->endName;

	}


}

added line "endName" to config


'endName'=>'shop',

and launching the application via


Yii::createApplication('CWebEndApplication',$config)->run();

If there any suggestions of better implementation, i will be glad to discuss it :)