PHP 7 from Docker container complete with Yii 2.0

Pretty cool, a PHP 7.0 (RC4) with Apache environment on Mac from scratch in a few minutes via Docker container:

https://gist.github.com/lgelfan/b4921393d41f345a15e9

Includes installation for minimal requirements to support Yii 2.0

Uses Vagrant + VirtualBox on Mac (or similar) or instead you can use any existing Docker host.

Yii CArrayDataProvider add case-sensitive option

In Yii if you use CArrayDataProvider for a data set, it will use PHP’s array_multisort for sorting, which is normally case sensitive so if you have any items that aren’t capitalized, it will mess up the order and is inconsistent with how MySql sorts.

And now that I realize this extra sorting step is happening (and it certainly makes sense to do it that way, Yii doesn’t know where my data originally came from) — I may re-think where I’m using this to see if it can be done via a database (CActiveDataProvider) search since I’m usually fetching the data from the db anyway and it would be more efficient to have MySql sort it at the time it’s requested.

In any case – if for whatever reason you are not using a db connection for the data or really do have to do some pre-processing before handing off to CArrayDataProvider, here is how you can add a case-sensitive switch:

Click here to view code

Override CArrayDataProvider to provide a custom sortData method and add an additional property to toggle the custom bit:

class myCArrayDataProvider extends CArrayDataProvider {
	public $casei = false;
 
	protected function sortData($directions)
	{
		if(empty($directions))
			return;
		$args=array();
		$dummy=array();
		foreach($directions as $name=>$descending)
		{
			$column=array();
			foreach($this->rawData as $index=>$data)
				$column[$index]=is_object($data) ? $data->$name : $data[$name];
			$args[]=&$column;
			$dummy[]=&$column;
			unset($column);
			$direction=$descending ? SORT_DESC : SORT_ASC;
			$args[]=&$direction;
			$dummy[]=&$direction;
			unset($direction);
		}
 
		if ($this->casei) { 
			for ($i = 0; $i < count($args); $i++) {
				$args[$i] = (is_array($args[$i])) ? 
                                          array_map('strtolower', $args[$i]) : $args[$i];
			}
		}
 
		$args[]=&$this->rawData;
		call_user_func_array('array_multisort', $args);
	}
}

Then when creating your dataProvider:

$dataProvider = new myCArrayDataProvider($proj_result, array(
  [rest of your params...]
));
$dataProvider->casei = true;

If you always wanted it case insensitive you could leave out the "casei" param.

Yii: use ajax function via htmlOptions attribute

If you want to trigger an ajax call on a Yii form element onchange, you can pass an array of ajax attributes as one of the “htmlOptions” like so:

<?php echo $form->textField($model,'my_input_field',array(
	'ajax' => array(
		'type'=>'POST', //request type
		'url'=>$this->createUrl('site/ajaxAction'), // url to call controller action
		'success'=>' function(data) { $(\'#my_output_field\').val(data) }',// function to call onsuccess 
             // "data" is returned data and function can be regular js or jQuery
             // here we are are updating the value of another field that has id "my_output_field"
	),
	'size'=>60,
	'maxlength'=>128,
)); ?>

and the (site) controller action would look something like:

public function actionAjaxAction() {
  [check/filter inputs...]
  [data functions...]
  echo $my_val_string;
  Yii::app()->end()
}

Yii auto-complete example

I didn’t see any concise examples of Yii autocomplete, particularly showing data fetched via a server request, so here is one:

widget function in view:

$this->widget('zii.widgets.jui.CJuiAutoComplete', array(
	'name'=>'person',
	'value'=>$model->person,
//	'source'=>$people, // <- use this for pre-set array of values
	'source'=>'/site/getNames',// <- path to controller which returns dynamic data
	// additional javascript options for the autocomplete plugin
	'options'=>array(
		'minLength'=>'1', // min chars to start search
		'select'=>'js:function(event, ui) { console.log(ui.item.id +":"+ui.item.value); }'
	),
	'htmlOptions'=>array(
		'id'=>'person',
		'rel'=>'val',
	),
));

controller function to filter and return data:

	function actionGetNames() {
	  if (!empty($_GET['term'])) {
		$sql = 'SELECT people_id as id, CONCAT(first_name," ",last_name) as value, first_name as label FROM people WHERE first_name LIKE :qterm ';
		$sql .= ' ORDER BY first_name ASC';
		$command = Yii::app()->db->createCommand($sql);
		$qterm = $_GET['term'].'%';
		$command->bindParam(":qterm", $qterm, PDO::PARAM_STR);
		$result = $command->queryAll();
		echo CJSON::encode($result); exit;
	  } else {
		return false;
	  }
	}

sample data output when user types an “r”, looks like:

[{"id": 1,"value": "Rachel Hammond","label": "Rachel"}, {"id": 18,"value": "Ross King","label": "Ross"}]

This is obviously a simple example but one that can easily be extended. In the example above the optional ‘select’ param is the js function once the user selects a value.

More info see CJuiAutoComplete and jqueryui.com/demos/autocomplete

Using your own jQuery file with Yii

(and have them play nice)

A common issue and one that I knew there was a Yii solution for but didn’t see clearly documented is how to include your own jQuery file, particularly on a site that has mixed pages where Yii includes it’s own version on some pages and not on others — which can result in jQuery loading twice and causing problems that are not always immediately obvious as to the cause.

In any case, this should do the trick. If you don’t need jQuery on every page, you can leave off or wrap the registerScriptFile line in a conditional and Yii will use your jQuery file when it needs it.

$cs=Yii::app()->clientScript;
$cs->registerScriptFile(Yii::app()->getBaseUrl() . '/js/libs/jquery.min.js', CClientScript::POS_HEAD);
$cs->scriptMap=array(
    'jquery.js'=>Yii::app()->getBaseUrl() . '/js/libs/jquery.min.js',
);

« Previous Entries