Yii - On what circumstances should we use clips?

Hello all,

Partials will be a view with no layout attached, for small non complex logic involved.

Layouts will be for common elements, header footer, column1, 3columns…

Widgets will be for elements that have a complex logic behind like calendars, galleries, and navigation menus (like cmenu widget);

Clips

This was all that I can read on Yii guide about it. :(

Calendar and Galleries sure are

. Hence, the trouble:

On what circumstances should we use clips ?

Thanks in advance.

Haha, up to now I haven’t heard of clips at all, but why don’t you try the forum search?

I found an application example here: http://www.yiiframework.com/forum/index.php/topic/1780-example-on-using-clips/

I see nothing there. No example of using clips at all. And, above all, any explanation about on what circumstances should we use or not clips.

:(

Imagine you have clientside-sortable portlets. With clips you can first record all the portlets in a default order. Then you can display them based on the order defined by the user. Simple example:





// record each portlet here in any order


...


$_COOKIE['portlet-order'] = 'login|poll|something-else'; // this order was set by the client


$portlets = explode('|', $_COOKIE['portlet-order']);


foreach (portlets as $portlet)

{

   echo $this->clips[$portlet];

}




Thanks.

Still not getting. Sorry. English is not my main language, and that could play a role here. As a plus, I don’t consider myself a great programmer so, that’s also an issue. All this to say: “Please have patience”

So:

So, portlet can be clips? So, for example, the "Poll" would be a clip ?

But the pull has a lot of logic involved. Shouldn’t that be a Widget ?

Or a clip could be a widget ?

:mellow:




$this->beginClip('login');

   $this->widget('LoginWidget');

$this->endClip();


$this->beginClip('poll');

   $this->widget('PollWidget');

$this->endClip();


$portlets = explode('|', $_COOKIE['portlet-order']);


foreach (portlets as $portlet)

{

   echo $this->clips[$portlet];

}



So with clips you can record different fragments of a page and then display them dynamically.

I’m not sure I get it yet. The above could be accomplished more easily using the $captureOutput argument of CController::widget.

A key difference it seems is that you can record arbitrary output between the beginClip and endClip.




$this->beginClip('login');

   $this->widget('LoginWidget');

   echo 'Some string';

   $this->renderPartial('aView');

   echo 'etc...';

$this->endClip();



and you can capture any number of them.

I should have phrased this as a question. I’ve never used clips.

Plus cant we just do that with partials anyway?

Yeah, but you can run clips in any controller - anywhere.

I use it from time to time.

Instead of passing arrays to sidebars and other elements, it’s much simpler to use a clip or two. And it’s cleaner as well.

For example, I have this in components/controller.php:


class Controller extends CController {


	public $sidebar_content = '';

	public $users_online = null;

	public $visitorTableName = '{{visitor}}';


	protected function beforeAction($action) {

    	if (isset(Yii::app()->user->id)) {

        	$user_id = Yii::app()->user->id;


        	//TODO: Don't do this every time the app runs??


        	$sql = "SELECT user_id FROM {$this->visitorTableName} WHERE user_id=:user_id";

        	if (Yii::app()->db->createCommand($sql)->bindValue(':user_id', $user_id)->queryScalar() === false)

            	$sql = "INSERT INTO {$this->visitorTableName} (user_id, last_activity) VALUES (:user_id, :last_activity)";

        	else

            	$sql = "UPDATE {$this->visitorTableName} SET last_activity=:last_activity WHERE user_id=:user_id";

        	Yii::app()->db->createCommand($sql)->bindValue(':user_id', $user_id)->bindValue(':last_activity', date('Y-m-d H:i:s'))->execute();

    	}


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

            	->select('u.id, username, TIMESTAMPDIFF(MINUTE, last_activity, UTC_TIMESTAMP())')

            	->from('{{usergroups_user}} u')

            	->join("{$this->visitorTableName} v", 'u.id=v.user_id')

            	->where('TIMESTAMPDIFF(MINUTE, last_activity, UTC_TIMESTAMP()) < 5')

            	->queryAll();


    	$this->users_online = $users;


    	$this->beginWidget('system.web.widgets.CClipWidget', array('id' => 'users_online'));

    	if (isset($this->users_online)) {

        	foreach ($this->users_online as $user)

            	if (isset($user)) {

                	echo '<b>' . ucfirst($user['username']) . '</b> <small>(';

                	echo 'Idle for ' . $user['TIMESTAMPDIFF(MINUTE, last_activity, UTC_TIMESTAMP())'] . ' minutes)</small><br/>';

            	}

    	} else {

        	echo 'none';

    	}

    	$this->endWidget();

    	$this->beginWidget('system.web.widgets.CClipWidget', array('id' => 'site_statistics'));

        	echo CHtml::openTag('p');

            	echo 'online: ' . Yii::app()->usercounter->getOnline() . '<br />';

            	echo 'today: ' . Yii::app()->usercounter->getToday() . '<br />';

            	echo 'yesterday: ' . Yii::app()->usercounter->getYesterday() . '<br />';

            	echo 'total: ' . Yii::app()->usercounter->getTotal() . '<br />';

            	echo 'maximum: ' . Yii::app()->usercounter->getMaximal() . '<br />';

            	echo 'date for maximum: ' . date("Y-m-d H:i:s", Yii::app()->usercounter->getMaximalTime()) . '<br />';

        	echo CHtml::closeTag('p');

    	$this->endWidget();


    	return true;

	}



Maybe not a prime example of good coding practices, but at least it makes it possible to use those two clips anywhere. ;)

Without cluttering up controllers/views.

you can also use clips to pass content to layouts from view file ;

clulumn2 :




      if(isset($this->clips['someSpecMenu'])){


        echo $this->clips['someSpecMenu'];

      }




in your action or view file:





   $this->beginClip('someSpecMenu');

   // echo  any content here ;

$this->endClip();






thus different controller can use a same layout file (column2) but in some area it can output different contents (menus , widgets , ad … and so no ) :D

@jacmoe, yiqing95, Y!!: Thanks for the info. I have to admit I never got the use of clips but they actually seem more flexible than partials or public controller attributes.

EDIT: Just tested it, so much better than the lame use of public properties :)

Sure the examples will help me out to do similar things when I found myself on the same or near circumstances. I still believe it would be helpful if we have, on a manual, some theoretical references about this, well organized that we can read and truly comprehend.

Thank you all for all your comments and examples provided that have helped.

Cheers,

mem

I’ve just gotten past a bit of the learning curve with clips, so I thought I’d share my current solution.

Basically, I wanted a re-useable CMenu sidebar widget for various departments of my site.

My controller looks like this (I’m using actions too):


class ExampleController extends Controller

{

    ...

    public function actions()

    {

        return array(...

	    'stories' => array(

	        'class' => 'application.controllers.example.StoriesAction',

	    ),

	);

    }

}

Then, my StoriesAction (controllers/example/StoriesAction.php) looks like this.


class StoriesAction extends CAction

{

    public function run()

    {

        ...

	$this->controller->renderPartial("_sidebar");

	$this->controller->layout = 'sidebarleft';

	$this->controller->render("stories");

    }

}

Then, in views/example/_sidebar.php:


$this->beginClip('sidebar');


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

	'activeCssClass'=>'active',

	'itemCssClass' => 'item',

        ...

));


$this->endClip();



The sidebarleft layout contains, among other things:


<?php echo $this->clips['sidebar']; ?>

<?php echo $content; ?>

This way, each controller can have its own sidebar, written as a single script, which is rendered into a clip and used in a global layout. Niiice.

One of the primary uses of clips, if my research is right, is server optimization. If you have a db query that takes a while to complete, you could save the result in a clip. Then when you run the query the first time it takes how eve long to complete, but for the next request the server just sends the clip. I believe there is a way, either programmer if() test or clip expire thing, to get fresh clip if underlying data changes.

Just my 2 cents 8)