Chiamare Widget In Un Modulo

Salve a tutti,

questa è la prima volta che scrivo su questo forum ed è la prima volta che utilizzo yii per i miei sviluppi.

In effetti sto lavorando con yii da due giorni, ma dopo aver letto la guida e i vari tutorial ho capito che ha davvero una potenzialità unica.

Ora veniamo al mio problema ;D

Sto cercando di realizzare una vista che implementa vari hook dove li posiziono nel file main.php, dove ogni hook contiene una serie di moduli che se attivi vengono visualizzati.

Ora il mio problema è questo, se voglio chiamare un widget da un modulo è possibile?

Premetto che non ho utilizzato i components ma i moduli.

Inoltre essendo nuovo dell’ambiente vi posto il codice per la gestione di ciò che ho fatto per capire se mi sto muovendo bene o meno.

Ho modificato la classe controller in questo modo per permettere il caricamento dei file media quali css e jquery, di seguito il codice:

Controller.php




<?php

/**

 * Controller is the customized base controller class.

 * All controller classes for this application should extend from this base class.

 */

class Controller extends CController

{

        public static $file_exists = array();

	/**

	 * @var string the default layout for the controller view. Defaults to '//layouts/column1',

	 * meaning using a single column layout. See 'protected/views/layouts/column1.php'.

	 */

	public $layout='//layouts/column1';

	/**

	 * @var array context menu items. This property will be assigned to {@link CMenu::items}.

	 */

	public $menu=array();

	/**

	 * @var array the breadcrumbs of the current page. The value of this property will

	 * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}

	 * for more details on how to specify this property.

	 */

	public $breadcrumbs=array();

        

        public $hook_top = array();

        

        public $hook_header = array();




        public function init()

        {


          $cssFile = $this->checkFileInclude(Yii::app()->theme->baseUrl.'/css/', 'css');


          arsort($cssFile);

          foreach($cssFile as $css){

              if($css == Yii::app()->theme->baseUrl.'/css/screen.css'){

                  Yii::app()->clientScript->registerCssFile($css, 'screen, projection');

              }else{

                  Yii::app()->clientScript->registerCssFile($css, '');

              }

          }

          

          Yii::app()->clientScript->registerCssFile(Yii::app()->theme->baseUrl.'/css/print/print.css', 'print');

          

          Yii::app()->clientScript->registerCoreScript('jquery');

          

          $this->hook_top = Hook::execute('displayTop');

          $this->hook_header = Hook::execute('displayHeader');

                  

          return parent::init();

        }

        

        public function checkFileInclude($folder, $ext){

            

            $files = glob('..'.$folder.'*.{'.$ext.'}', GLOB_BRACE);

            

            foreach($files as $file) {

                    $f[] = str_replace('..', '', $file);

            }

            return $f;

        }

        

        public static function file_exists($filename)

	{

		if (!isset(self::$file_exists[$filename]))

			self::$file_exists[$filename] = file_exists($filename);

		return self::$file_exists[$filename];

	}

}



Poi ho creato una classe Hook.php e questo è il contenuto:




<?php


/**

 * This is the model class for table "yii_hook".

 *

 * The followings are the available columns in table 'yii_hook':

 * @property integer $id_hook

 * @property string $title_hook

 * @property string $description_hook

 * @property integer $position_hook

 *

 * The followings are the available model relations:

 * @property YiiHookModule[] $yiiHookModules

 */

class Hook extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'yii_hook';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('title_hook, description_hook, position_hook', 'required'),

			array('position_hook', 'numerical', 'integerOnly'=>true),

			array('title_hook', 'length', 'max'=>64),

			array('description_hook', 'length', 'max'=>124),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id_hook, title_hook, description_hook, position_hook', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'Hook' => array(self::HAS_MANY, 'Hook', 'id_hook'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id_hook' => 'Id Hook',

			'title_hook' => 'Title Hook',

			'description_hook' => 'Description Hook',

			'position_hook' => 'Position Hook',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id_hook',$this->id_hook);

		$criteria->compare('title_hook',$this->title_hook,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return Hook the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

        

        public static function execute($hook_name)

        {

            $module = self::moduleList($hook_name);

            

            if (empty($module))    

            return '';


            foreach($module as $mod){

                // Instanzio la classe di ogni modulo ricevuto per nome

                if(Controller::file_exists(Yii::app()->basePath.'/modules/'.$mod['module'].'/'.$mod['module'].'Module.php')){

                $instance = Yii::app()->getModule($mod['module']);

                //instanzio ogni modulo attivo

                return $instance->initialize();

                }

            }

        }


        public static function moduleList($hook_name)

        {    

            $list = '';

            $configuration = Configuration::model()->findByAttributes(array('key'=>'CLEAR_CACHE'));

            $cache_id = 'hook_module_execute_list-'.strtolower($hook_name);

            

            //se il contenuto non è in cache oppure se forzo la rigenerazione della cache rigenero la cache

            if(!Yii::app()->cache->get($cache_id) || $configuration->value){

                

            $listModule = Yii::app()->db->createCommand()

                    ->select('m.id_module, m.name_module, hm.position')

                    ->from('yii_hook h')

                    ->join('yii_hook_module hm', 'h.id_hook=hm.id_hook')

                    ->join('yii_module m', 'hm.id_module=m.id_module')

                    ->where('h.title_hook=:title_hook', array(':title_hook'=>$hook_name))

                    ->andWhere('m.active=:active', array(':active'=>1))

                    ->order('hm.position')

                    ->queryAll();

            

            foreach ($listModule as $module){

                $list[$module['name_module']] = array(

                    'module' => $module['name_module'],

                    'id_module' => $module['id_module'],

                    'position' => $module['position']

                );

                Yii::app()->cache->set($cache_id, $list, 3600, new CFileCacheDependency($cache_id));

                $list = Yii::app()->cache->get($cache_id);

            }

        }else{

            $list = Yii::app()->cache->get($cache_id);

        }

            

            // list contiene i moduli attivi per hook

            return $list;

        }

}




Mentre nel main.php del tema richiamo gli hook in questo modo:


<?php echo $this->hook_top; ?>

Ora ho creato un modulo chiamato Search (dove conterrà il box per la ricerca), nel file SearchModule.php ho questo:




<?php


class SearchModule extends CWebModule

{

	public function init()

	{

		// this method is called when the module is being created

		// you may place code here to customize the module or the application


		// import the module-level models and components

		$this->setImport(array(

			'Search.models.*',

			'Search.components.*',

		));  

                

	}

        

        public function initialize()

        {

            return $this->getContent();

        }

        

        public function getContent()

        {

            //qui dovrò richiamare un widget per la ricerca

        }


        public function beforeControllerAction($controller, $action)

	{

		if(parent::beforeControllerAction($controller, $action))

		{

			// this method is called before any module controller action is performed

			// you may place customized code here

			return true;

		}

		else

			return false;

	}

}




Spero di essere stato chiaro e di non aver esagerato con ciò che ho scritto e sopratutto sapere se cosi mi muovo bene o sto perdendo la logica di yii ::)

A me sembra che tu stia cercando di usare la vista di Yii come se fosse una sorta di wordpress o joomla. Dici che vuoi usare un widget per la ricerca, ma la ricerca la fa il model, il widget serve per alterare la vista, a prescindere da quello che fa.

In effetti sto cercando di capire come fare se volessi fare un web con yii fatto a widget cioè componibile, spostando i vari blocchi per completare l’interfaccia. Si in effetti come fanno i cms che hai nominato, però sfruttando la potenza di questo framework. Questo è dovuto al fatto che se faccio ad esempio un e-commerce per un cliente e poi devo fare un nuovo e-commerce per un ulteriore cliente, dovrò cambiare solo il layout del nuovo avendo tutte le basi già pronte e quindi perdendo molto meno tempo.

Comunque ho risolto dopo varie prove ho visto che posso farlo.

Grazie

Non dire solo che hai risolto un problema, dicci anche come hai fatto a risolverlo: potrebbe essere utile per chi verrà a trovarci in questo forum.

PS. Consiglio spassionato: disaccoppia tutto quello che scrivi. Io per esempio tendo a scrivere tutto in dei moduli. In questo modo posso spostare intere cartelle che contengono widget controller e model.

Si certo scusami, ho fatto in questo modo.

In primis nella cartella protected/extensions/ ho creato una cartella Search, all’interno ho inserito i seguenti file e cartelle:

assets/

views/

SearchExt.php (che è il file chiamato dalla classe Hook che scriverò di seguito).

Contenuto del file models/Hook.php




<?php


/**

 * This is the model class for table "yii_hook".

 *

 * The followings are the available columns in table 'yii_hook':

 * @property integer $id_hook

 * @property string $title_hook

 * @property string $description_hook

 * @property integer $position_hook

 *

 * The followings are the available model relations:

 * @property YiiHookModule[] $yiiHookModules

 */

class Hook extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'yii_hook';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('title_hook, description_hook, position_hook', 'required'),

			array('position_hook', 'numerical', 'integerOnly'=>true),

			array('title_hook', 'length', 'max'=>64),

			array('description_hook', 'length', 'max'=>124),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id_hook, title_hook, description_hook, position_hook', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'Hook' => array(self::HAS_MANY, 'Hook', 'id_hook'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id_hook' => 'Id Hook',

			'title_hook' => 'Title Hook',

			'description_hook' => 'Description Hook',

			'position_hook' => 'Position Hook',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id_hook',$this->id_hook);

		$criteria->compare('title_hook',$this->title_hook,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return Hook the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

        

        /**

        * Metodo che viene chiamato dal controller di base ovvero controller.php

        * all'interno del metodo init()

        */

        public static function execute($hook_name)

        {

            $module = self::moduleList($hook_name);

            

            if (empty($module))    

            return '';


            foreach($module as $mod => $v){

                // Instanzio la classe di ogni modulo ricevuto per nome


                    if(Controller::file_exists(Yii::app()->basePath.'/extensions/'.$mod.'/'.$mod.'Ext.php')){


                        $class = $mod.'Ext';

                        

                        Yii::import('application.extensions.'.$mod.'.'.$class);

                        

                        $ext = new $class();

                        //chiamo metodo getWidget() per l'inizializzazione 

                        $output[] = $ext->getWidget();

                }

            }


            return implode($output);

        }


        public static function moduleList($hook_name)

        {    

            $list = '';

            $configuration = Configuration::model()->findByAttributes(array('key'=>'CLEAR_CACHE'));

            $cache_id = 'hook_module_execute_list-'.strtolower($hook_name);

            

            if(!Yii::app()->cache->get($cache_id) || $configuration->value){

                

            $listModule = Yii::app()->db->createCommand()

                    ->select('m.id_module, m.name_module, hm.position')

                    ->from('yii_hook h')

                    ->join('yii_hook_module hm', 'h.id_hook=hm.id_hook')

                    ->join('yii_module m', 'hm.id_module=m.id_module')

                    ->where('h.title_hook=:title_hook', array(':title_hook'=>$hook_name))

                    ->andWhere('m.active=:active', array(':active'=>1))

                    ->order('hm.position')

                    ->queryAll();

            

            foreach ($listModule as $module){

                $list[$module['name_module']] = array(

                    'module' => $module['name_module'],

                    'id_module' => $module['id_module'],

                    'position' => $module['position']

                );

                Yii::app()->cache->set($cache_id, $list, 3600, new CFileCacheDependency($cache_id));

                $list = Yii::app()->cache->get($cache_id);

            }

        }else{

            $list = Yii::app()->cache->get($cache_id);

        }

            

            // list contiene i moduli attivi per hook

            return $list;

        }

        

        public static function getNameHook($id_hook)

        {

            $criteria = new CDbCriteria;

            $criteria->select = array('title_hook');

            $criteria->addSearchCondition('id_hook', $id_hook);

            $data = Hook::model()->find($criteria);

            return $data->title_hook;

        }

}




All’interno della cartella extensions/SearchExt.php ho questo:




<?php


class SearchExt extends CWidget {

    

    public $name = 'Search';

    

    public $model = array();

    

    public $_HOOK; 




    public function run() {

        

        $this->setHook();

        

        //poichè può essere posto sia in alto che in una colonna

        if($this->_HOOK  == 'Top'){

            $this->render('search'); // view 

        }elseif($this->_HOOK  == 'leftColumn'){

            $this->render('searchLeft'); // view 

        }

        

    }

    

    /**

     * Metodo chiamato dall'hook

     * @return type

     */

    public function getWidget()

    {

        return $this->returnWidget();

    }

    

    public function setHook()

    {

        $module = new Module;

        $id_module = $module->getIdByName($this->name);

        $cache_id = 'hook_module_position-module-'.$id_module;

        

        if(!Yii::app()->cache->get($cache_id)){

            $this->_HOOK = HookModule::isHook($id_module);

            Yii::app()->cache->set($cache_id, $this->_HOOK, 3600, new CFileCacheDependency($cache_id));

        }else{

            $this->_HOOK = Yii::app()->cache->get($cache_id);

        }

    }


    

    public function returnWidget()

    {

        // aggiungo il file css per autocomplete

        Yii::app()->clientScript->registerCssFile(Yii::app()->clientScript->getCoreScriptUrl().'/autocomplete/jquery.autocomplete.css');

        

        // ricavo il path nuovo dell'estensione nella classe extensions che si trova nella cartella model (dopo mostrerò il codice)

        $assetUrl = Extensions::getPathModule($this->name);

        Yii::app()->clientScript->registerCssFile($assetUrl.'/search.css');

        

        // metto il contenuto di widget in una variabile

        ob_start();

        $this->widget('SearchExt'); // nome classe

        $widget=ob_get_contents();

        ob_end_clean();

        return $widget;

    }   

}


?>




Poi nella cartella views/search.php ho questo:




<?php


$this->widget('zii.widgets.jui.CJuiAutoComplete', array(

            'name' => 'search-ext',

            'sourceUrl' => array('Site/suggest'), //file suggest.php nella root

            'value' => 'Cerca...',

            'options' => array(

                'showAnim' => 'fold',

                'minLength'=>'2',

                'select' => 'js:function(event, ui){ jQuery("#Daytrip_idNo").val(ui.item["id"]); }'

            ),

            'htmlOptions'=>array(

                        'size'=>'40',

                        'onClick' => 'document.getElementById("search-ext").value=""'

                        ),

    ));

    ?>



poi nella cartella assets/search.css ho questo:




#search-ext {

    float: right;

}


// manca ancora il codice per la visualizzazione in una colonna



Mentre nella cartella models/Extensions.php ho questo:




<?php


class Extensions {

    

    public static $name;




    public static function setPathModule()

        {

            return Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('application.extensions.'.self::$name.'.assets'));

        }


    public function getPathModule($name)

    {

        self::$name = $name;

        return self::setPathModule();

    }

    

}


?>




Mentre nel controller di base che trovo in components/controller.php all’interno del metodo init() ho questo:




$this->hook_top = Hook::execute('Top');



Ed infine nel file del template per chiamare l’hook con tutte le estensioni faccio questo:


<?php echo $this->hook_top; ?>

Questo è tutto il codice penso di non aver dimenticato nessuna parte.

Che dici posto in questo modo va bene oppure sto facendo una grande confuzione :D ?

Cosa intendi quando dici

.

Grazie

Che il tuo codice deve essere disaccoppiato: non deve dipendere da altro codice nella tua applicazione.

Ok, si ora ho capito.