<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sud Web Design</title>
	<atom:link href="http://sudwebdesign.com/feed" rel="self" type="application/rss+xml" />
	<link>http://sudwebdesign.com</link>
	<description>Just another WordPress site</description>
	<lastBuildDate>Tue, 21 Feb 2012 10:55:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Changing the width of a filter column in CGridview</title>
		<link>http://sudwebdesign.com/changing-the-width-of-a-filter-column-in-cgridview/573</link>
		<comments>http://sudwebdesign.com/changing-the-width-of-a-filter-column-in-cgridview/573#comments</comments>
		<pubDate>Tue, 21 Feb 2012 10:07:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[cgridview]]></category>
		<category><![CDATA[cgridview column]]></category>
		<category><![CDATA[cgridview column width]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=573</guid>
		<description><![CDATA[I recently spent an hour or so trying to reduce the width of columns in a CGridView. As I was trying to squash the grid into a narrow space, I wanted some columns to be narrower than others. I tried &#8230; <a href="http://sudwebdesign.com/changing-the-width-of-a-filter-column-in-cgridview/573">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently spent an hour or so trying to reduce the width of columns in a CGridView. As I was trying to squash the grid into a narrow space, I wanted some columns to be narrower than others.</p>
<p>I tried setting the headerHtmlOptions and the HtmlOptions and I could see these coming through in the HTML but found that it was the width of the input boxes in the filter row that was throwing out width of the column.</p>
<p>I finally found a solution that works (for me). I know this is a bit of a hack but it works!</p>
<p>I ended up using attribute names in CSS to determine the max-width of the input boxes as follows:</p>
<pre>input[name="Properties[ref]"]
{
    max-width: 55px;
}</pre>
<p>It doesn&#8217;t seem quite the right way to do it, but it works. I would be interested if anyone has found a better way &#8230;</p>
<div id="attachment_574" class="wp-caption alignleft" style="width: 735px"><a href="http://sudwebdesign.com/wp-content/uploads/2012/02/gridview-column_width.png"><img class=" wp-image-574  " title="gridview-column_width" src="http://sudwebdesign.com/wp-content/uploads/2012/02/gridview-column_width.png" alt="" width="725" height="150" /></a><p class="wp-caption-text">Setting the width of columns in a CGridView</p></div>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/changing-the-width-of-a-filter-column-in-cgridview/573/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; Exit or End a Controller action</title>
		<link>http://sudwebdesign.com/yii-exit-or-end-a-controller-action/556</link>
		<comments>http://sudwebdesign.com/yii-exit-or-end-a-controller-action/556#comments</comments>
		<pubDate>Mon, 13 Feb 2012 16:59:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[controller action end]]></category>
		<category><![CDATA[end]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[terminate]]></category>
		<category><![CDATA[terminate controller action]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=556</guid>
		<description><![CDATA[To exit or end processing in a controller action use the end  function Yii::app()-&#62;end(); For example; this may be used to terminate processing if invalid, incorrect or missing parameters are passed if (empty($_GET)) Yii::app()-&#62;end();]]></description>
			<content:encoded><![CDATA[<p>To exit or end processing in a controller action use the <em>end</em>  function</p>
<pre>       	Yii::app()-&gt;end();</pre>
<p>For example; this may be used to terminate processing if invalid, incorrect or missing parameters are passed</p>
<pre>   if (empty($_GET))
       	Yii::app()-&gt;end();</pre>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/yii-exit-or-end-a-controller-action/556/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; Uploading and saving images</title>
		<link>http://sudwebdesign.com/yii-uploading-and-saving-images/541</link>
		<comments>http://sudwebdesign.com/yii-uploading-and-saving-images/541#comments</comments>
		<pubDate>Sun, 05 Feb 2012 12:05:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[photo model]]></category>
		<category><![CDATA[upload image]]></category>
		<category><![CDATA[yii]]></category>
		<category><![CDATA[yii photo]]></category>
		<category><![CDATA[yii photo management]]></category>
		<category><![CDATA[yii photo model]]></category>
		<category><![CDATA[yii php]]></category>
		<category><![CDATA[yii upload]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=541</guid>
		<description><![CDATA[updated:  17-Feb-2012 A simple example of a method to upload and save images.  In this example, I created a &#8220;Photo&#8221; model that saves caption &#38; alt text info to be displayed with the images.  If you create a similar model &#8230; <a href="http://sudwebdesign.com/yii-uploading-and-saving-images/541">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>updated</strong>:  17-Feb-2012</p>
<p>A simple example of a method to upload and save images.  In this example, I created a &#8220;Photo&#8221; model that saves caption &amp; alt text info to be displayed with the images.  If you create a similar model using Gii and then apply these changes.</p>
<p>Controller:<br />
Here, I&#8217;m just showing you the create action. obviously, you will also need to code the Update and Delete actions as well.<br />
When uploading photos, I prefer to rename the photo with a randomly generated name and this is included in the UpdatePhoto function below.<br />
Also, I crunch photos to a maximum size, this stops users trying to upload their 2500px 21Mb photo! The UpdatePhoto function will also create a thumbnail and store that in a &#8220;thumbs&#8221; sub-directory.</p>
<pre>	public function actionCreate()
	{
		$model=new Photos;

		if(isset($_POST['Photos']))
		{
                    $model-&gt;attributes=$_POST['Photos'];
                    $myfile = CUploadedFile::getInstance($model,'image');
                    $model-&gt;image=$myfile;

                    if($model-&gt;save())
                        $this-&gt;updatePhoto($model, $myfile);

					$this-&gt;redirect('view'.'id'=&gt;$model-&gt;id);
		}

        $this-&gt;render('create',array(
			'model'=&gt;$model,
		));
	}

        /*--------------
        * Upload and crunch an image
	*
        ----------------*/
        public function updatePhoto($model, $myfile ) {
           if (is_object($myfile) &amp;&amp; get_class($myfile)==='CUploadedFile') {
                $ext = $model-&gt;image-&gt;getExtensionName();

		//generate a filename for the uploaded image based on a random number
		// but check that the random number has not already been used
                if ($model-&gt;filename=='' or is_null($model-&gt;filename)) {
                    $n=1;
                    // loop until random is unqiue - which it probably is first time!
                    while ($n&gt;0) {
                        $rnd=dechex(rand()%999999999);
                        $filename=$model-&gt;property-&gt;ref . '_' . $rnd . '.' . $ext;
                        $n=Photos::model()-&gt;count('filename=:filename',array('filename'=&gt;$filename));
                    }
                $model-&gt;filename=$filename;
                }

                $model-&gt;save();

                $model-&gt;image-&gt;saveAs($model-&gt;getPath());  //model-&gt;getPath see below

                $image = Yii::app()-&gt;image-&gt;load($model-&gt;getPath());
		//Crunch the photo to a size set in my System Options Table
		//I hold the max size as 800 meaning to fit in an 800px x 800px square
                $size=$this-&gt;getOption('PhotoLarge');
                $image-&gt;resize($size[0], $size[0])-&gt;quality(75)-&gt;sharpen(20);
                $image-&gt;save(); 

		// Now create a thumb - again the thumb size is held in System Options Table
		$size=$this-&gt;getOption('PhotoThumb');
                $image-&gt;resize($size[0], $size[0])-&gt;quality(75)-&gt;sharpen(20);
                $image-&gt;save($model-&gt;getThumb()); // or $image-&gt;save('images/small.jpg');
                return true;
             } else return false;
        }</pre>
<p>View:<br />
The view is pretty standard, note the <em>enctype</em> has been changed to multipart.</p>
<p>Note also, the function getThumbnail from the photo model which returns the thumbnail image.  the code for this is given below.</p>
<pre>&lt;div class="form" &gt;
    &lt;div id="success"&gt;
    &lt;/div&gt;
    &lt;?php $form=$this-&gt;beginWidget('CActiveForm', array(
            'enableAjaxValidation'=&gt;true,
            'id'=&gt;'formPhoto',
        'htmlOptions'=&gt;array('enctype'=&gt;'multipart/form-data',
            ),
    )); ?&gt;

	&lt;p class="note"&gt;Fields with &lt;span class="required"&gt;*&lt;/span&gt; are required.&lt;/p&gt;

	&lt;div class="row" &gt;
                &lt;?php echo $model-&gt;getThumbnail(); ?&gt;
            &lt;br&gt;
		&lt;?php echo $form-&gt;labelEx($model,'filename'); ?&gt;
                &lt;?php echo $form-&gt;hiddenField($model, 'id'); ?&gt;
        	&lt;?php echo $form-&gt;hiddenField($model, 'property_id'); ?&gt;
                &lt;?php echo CHtml::activeFileField($model, 'image'); // see comments below ?&gt;
        &lt;/div&gt;

	&lt;div class="row"&gt;
		&lt;?php echo $form-&gt;labelEx($model,'caption'); ?&gt;
		&lt;?php echo $form-&gt;textArea($model,'caption',array('rows'=&gt;6, 'cols'=&gt;50)); ?&gt;
	&lt;/div&gt;

	&lt;div class="row"&gt;
		&lt;?php echo $form-&gt;labelEx($model,'alt_text'); ?&gt;
		&lt;?php echo $form-&gt;textField($model,'alt_text',array('rows'=&gt;6, 'cols'=&gt;50)); ?&gt;
	&lt;/div&gt;

	&lt;div class="row"&gt;
		&lt;?php echo $form-&gt;labelEx($model,'sort_order'); ?&gt;
		&lt;?php echo $form-&gt;textField($model,'sort_order'); ?&gt;
	&lt;/div&gt;

	&lt;div class="row buttons" id="dvPhotoSubmit"&gt;
		&lt;?php echo CHtml::submitButton($model-&gt;isNewRecord ? 'Create' : 'Save'); ?&gt;
                &lt;?php echo CHtml::button('Cancel',array('onclick'=&gt;"window.parent.$('#cru-dialog').dialog('close');window.parent.$('#cru-frame').attr('src','');")); ?&gt;
 	&lt;/div&gt;

&lt;?php $this-&gt;endWidget(); ?&gt;
&lt;/div&gt;&lt;!-- form --&gt;</pre>
<p>Model</p>
<pre>public function getThumbnail(){
         // here i return the image
            if (!empty($this-&gt;filename) &amp;&amp; $this-&gt;filename!='')
             return CHtml::image($this-&gt;getURL(),$this-&gt;alt_text,array('width'=&gt;options::model()-&gt;getOption('PhotoThumb').'px','max-height'=&gt;options::model()-&gt;getOption('PhotoThumb').'px'
         ));
        }
	public function getPath($all=true){
            if (is_null($this-&gt;_PhotoPath)) {
                 // I hold the image path and system directory separator in the config/main.php
                 // this is because I develop on a windows server and normally deploy on Linux
                 $this-&gt;_PhotoPath=Yii::app()-&gt;params['imagePATH'];
                 $this-&gt;_PathSep=Yii::app()-&gt;params['pathSep'];
            }
            $path=$this-&gt;_PhotoPath.$this-&gt;_PathSep;
            if ($all) $path.=$this-&gt;filename;
            return $path;
        }</pre>
<p>edit:  I should have mentioned before that the model has a dummy field to store the bitmap image.  Use a variable definition &#8216;Public $image&#8217; and add a validation rule as safe.  This will enable the digital image to be saved in the model by the controller using the line</p>
<p><em>$model-&gt;attributes=$_POST['Photos'];</em></p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/yii-uploading-and-saving-images/541/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Date validation in Yii</title>
		<link>http://sudwebdesign.com/date-validation-in-yii/528</link>
		<comments>http://sudwebdesign.com/date-validation-in-yii/528#comments</comments>
		<pubDate>Wed, 01 Feb 2012 07:42:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[yii]]></category>
		<category><![CDATA[yii date range]]></category>
		<category><![CDATA[yii date range validation]]></category>
		<category><![CDATA[yii date ranges]]></category>
		<category><![CDATA[yii date validation]]></category>
		<category><![CDATA[yii validation]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=528</guid>
		<description><![CDATA[Moving on from my last post on Yii validation rules for text fields, next I am going to be looking at validating dates and date ranges. The date validator CDateValidator was added to Yii in release 1.1.7 and provides an easy &#8230; <a href="http://sudwebdesign.com/date-validation-in-yii/528">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Moving on from my last post on Yii validation rules for<a title="Yii – Further model validation" href="http://sudwebdesign.com/yii-further-model-validation/439"> text fields</a>, next I am going to be looking at validating dates and date ranges.</p>
<p>The date validator <a href="http://www.yiiframework.com/doc/api/CDateValidator">CDateValidator</a> was added to Yii in release 1.1.7 and provides an easy method to validate that a field contains a date, time or datetime, with the following parameters.</p>
<p><em>format</em> option enables you to specify the date format or a list of date formats in an array.</p>
<p><em>allowEmpty</em> - whether to allow empty or null values</p>
<p>for example:</p>
<pre>public function rules()
{
return array(
           // multiple formats specified to allow for 01/02/20012 and 1/02/2012
           array('reservation_from, reservation_to ', 'date', 'format'=&gt;array('dd/MM/yyyy','d/MM/yyyy'), 'allowEmpty'=&gt;true),
           array('created_dt, last_updated, ', 'date', 'format'=&gt;'yyyy-MM-dd HH:mm:ss', 'allowEmpty'=&gt;false),
  );
}</pre>
<p>So now we can be sure that the user has input valid date formats &#8211; what about date ranges.</p>
<p>If we wanted to check that the <em>reservation_to</em> is greater than the <em>reservation_from</em> we could perhaps use the <em>compare</em> validator for date ranges as follows:</p>
<pre>  array('reservation_to','compare','compareAttribute'=&gt;'reservation_from','operator'=&gt;'&gt;', 'allowEmpty'=&gt;true,'message'=&gt;'{attribute} must be greater than "{compareValue}".')</pre>
<p>So, wouldn&#8217;t life be nice and easy if this code worked &#8230;. but it doesn&#8217;t!</p>
<p>The date comparison validator uses datetimestamps.  It does not convert textual dates into timestamps.  Therefore the date in the format &#8220;dd/mm/yyyy&#8221; of 16/01/2012 is greater than 10/02/2012.</p>
<p>It looks as though we will still need to build a custom function to convert these dates to datetimestamps first and then do the comparison test.</p>
<p>So here is date function to do that validation.</p>
<pre>        public function dateCompare($attribute,$params) {

            if (empty($params['compareAttribute']) || empty($params['operator']))
               $this-&gt;addError($attribute, 'Invalid Parameters to dateCompare');

            $compareTo=$this-&gt;$params['compareAttribute'];

            if($params['allowEmpty'] &amp;&amp; (empty($this-&gt;$attribute) || empty($compareTo)))
		return;

            //set default format if not specified
            $format=(!empty($params['format']))? $params['format'] : 'dd/MM/yyyy';
            //default operator to &gt;
            $compare=(!empty($params['operator'])? $params['operator'] : "&gt;";

            $start=CDateTimeParser::parse($this-&gt;$attribute,$format);
            $end=CDateTimeParser::parse($compareTo,$format);
            //a little php trick - safe than eval and easier than a big switch statement
            if (version_compare($start,$end,$compare)) {
                    return;
            } else {
                    $this-&gt;addError($attribute, "start date is not $compare end date");
            }
        }</pre>
<p>and then we can change the validation rules as follows:</p>
<pre>{
return array(
           array('reservation_from, reservation_to ', 'date', 'format'=&gt;array('dd/MM/yyyy','d/MM/yyyy'), 'allowEmpty'=&gt;true),
           array('created_dt, last_updated, ', 'date', 'format'=&gt;'yyyy-MM-dd HH:mm:ss', 'allowEmpty'=&gt;false),
           array('reservation_to','dateCompare','compareAttribute'=&gt;reservation_from','operator'=&gt;'&gt;', 'allowEmpty'=&gt;true),
  );
}</pre>
<p>And there you have it &#8211; valid dates and date ranges in a nutshell. Happy coding!</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/date-validation-in-yii/528/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; User defined rules for Access rights</title>
		<link>http://sudwebdesign.com/yii-user-defined-rules-for-access-rights/475</link>
		<comments>http://sudwebdesign.com/yii-user-defined-rules-for-access-rights/475#comments</comments>
		<pubDate>Tue, 24 Jan 2012 13:10:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[access rules]]></category>
		<category><![CDATA[authenticated user]]></category>
		<category><![CDATA[web security]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=475</guid>
		<description><![CDATA[A key part of a web application is access security. Who can see what data, who can do what actions... <a href="http://sudwebdesign.com/yii-user-defined-rules-for-access-rights/475">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2> Yii Access Control Rules</h2>
<p>A key part of a web application is access security. Who can see what data, who can do what actions.</p>
<p>Within Yii the first layer of access security is defined within the controller where access control rules are defined for each action.</p>
<p>The default access rules created by the code generator in Gii are ;</p>
<ol>
<li>&#8216;All Users&#8217; &#8211; anybody is allowed to access these functions, which would relate to all visitors to your website</li>
<li>&#8216;Authenticated User&#8217; &#8211; those users which have logged in using whatever user authentication system you have chosen to use</li>
<li>&#8216;Admin&#8217; User &#8211; in fact this means a User called <em>admin</em> rather than any user defined as a super-user!</li>
</ol>
<p>However, using other parameters of the accessRules you can setup more advanced security algorithms.</p>
<p></p>
<h4>Expression</h4>
<p>The <em>expression</em> property allows you to define a function that will be called resulting in a true or false responses to whether the current user is able to access the listed functions.</p>
<p>For example, in the following code I have setup a function within the same controller called <em>isAdmin</em> which returns true or false as to whether the current user has super-user pivileges.<br />
</p>
<pre>	/**
	 * Specifies the access control rules.
	 * This method is used by the 'accessControl' filter.
	 * @return array access control rules
	 */
	public function accessRules()
	{
		return array(
			...
			array('allow', // allow admin user to perform 'admin' and 'delete' actions
				'actions'=&gt;array('delete', 'admin'),
				'expression'=&gt;'Yii::app()-&gt;controller-&gt;isAdmin()',
			),
			...
		);
	}</pre>
<h4>IP address</h4>
<p>The <em>ips</em> property will restrict access to a certain list of ip addresses:-</p>
<pre>			array('allow', // allow admin user to perform 'admin' and 'delete' actions
				'actions'=&gt;array('delete', 'admin'),
				'ips'=&gt;'127.0.0.1, 192.168.0.1',
			),</pre>
<h4>Further Access Rules</h4>
<p>The <a href="http://www.yiiframework.com/doc/api/1.1/CAccessControlFilter">Yii documentation</a> mentions other rules as follows:-</p>
<pre>array(
  'allow',  // or 'deny'
  // optional, list of action IDs (case insensitive) that this rule applies to
  // if not specified, rule applies to all actions
  'actions'=&gt;array('edit', 'delete'),
  // optional, list of controller IDs (case insensitive) that this rule applies to
  'controllers'=&gt;array('post', 'admin/user'),
  // optional, list of usernames (case insensitive) that this rule applies to
  // Use * to represent all users, ? guest users, and @ authenticated users
  'users'=&gt;array('thomas', 'kevin'),
  // optional, list of roles (case sensitive!) that this rule applies to.
  'roles'=&gt;array('admin', 'editor'),
  // optional, list of IP address/patterns that this rule applies to
  // e.g. 127.0.0.1, 127.0.0.*
  'ips'=&gt;array('127.0.0.1'),
  // optional, list of request types (case insensitive) that this rule applies to
  'verbs'=&gt;array('GET', 'POST'),
  // optional, a PHP expression whose value indicates whether this rule applies
  'expression'=&gt;'!$user-&gt;isGuest &amp;&amp; $user-&gt;level==2',
  // optional, the customized error message to be displayed
  // This option is available since version 1.1.1.
  'message'=&gt;'Access Denied.',
)</pre>
<p>If you have any useful rules, please feel free to share them below&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/yii-user-defined-rules-for-access-rights/475/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replace Windows Shell</title>
		<link>http://sudwebdesign.com/replace-windows-shell/470</link>
		<comments>http://sudwebdesign.com/replace-windows-shell/470#comments</comments>
		<pubDate>Fri, 20 Jan 2012 08:23:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Misc Tutorials]]></category>
		<category><![CDATA[Yii]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[dos-shell]]></category>
		<category><![CDATA[windows shell]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=470</guid>
		<description><![CDATA[If you&#8217;re like me and like the bash interface on linux then here is a really quick and easy way to replace the windows shell with a linux based bash interface. http://stackoverflow.com/a/4144747/1145818]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re like me and like the bash interface on linux then here is a really quick and easy way to replace the windows shell with a linux based bash interface.</p>
<p><a href="http://stackoverflow.com/a/4144747/1145818">http://stackoverflow.com/a/4144747/1145818</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/replace-windows-shell/470/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; Relations using a non-primary key</title>
		<link>http://sudwebdesign.com/relations-using-a-non-primary-key/451</link>
		<comments>http://sudwebdesign.com/relations-using-a-non-primary-key/451#comments</comments>
		<pubDate>Thu, 19 Jan 2012 11:39:53 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[cativerecord]]></category>
		<category><![CDATA[cgridview]]></category>
		<category><![CDATA[join on]]></category>
		<category><![CDATA[relations]]></category>
		<category><![CDATA[scopes]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=451</guid>
		<description><![CDATA[Often mistakes you make in your database design stage come around and bite you in the butt later! My Mistake I&#8217;m just testing a new reservation system that should be going live soon and it&#8217;s looking really good, expected results &#8230; <a href="http://sudwebdesign.com/relations-using-a-non-primary-key/451">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h3>Often mistakes you make in your database design stage come around and bite you in the butt later!</h3>
<h2>My Mistake</h2>
<p>I&#8217;m just testing a new reservation system that should be going live soon and it&#8217;s looking really good, expected results are bang on, the system is nice and stable, and (even better) easy to navigate.</p>
<p>However, I just clicked on a sortable column in a gridview and realised that it was sorting on the alphabetic value of the column rather than the order that the client might expect.   Added to that, in the original design, I used the lookup code and not the ID in the foreign key table! HELP!</p>
<p>This is a status column and therefore, in a business workflow, the customer will expect the column to appear in the order that these things happen in the business.  Therefore, I&#8217;m going to have to get the sort order from my Lookup table that has a column &#8216;<em>sort_order&#8217;.</em></p>
<p><strong><em>subnote: I believe this kind of attention to detail makes the difference between just a contented customer and a truly ecstatic customer!</em></strong></p>
<h2>Summary</h2>
<p>Problem:  A CGridview using a column that links to another table but not using the primary key.</p>
<p>Example:</p>
<p><a href="http://sudwebdesign.com/wp-content/uploads/2012/01/option_code.png"><img class="wp-image-459 alignnone" title="option_code" src="http://sudwebdesign.com/wp-content/uploads/2012/01/option_code.png" alt="" width="300" height="178" /></a></p>
<h2>Solution</h2>
<p>A stop gap solution is to define the relation between the reservations table and the lookup table using a column other than the primary key of the lookup table.  Obviously, the better solution would be to change the status column to hold the ID of the lookup rather than the lookup-code but that will have to wait for another day.</p>
<p>I couldn&#8217;t find any absolute way of doing this in the documentation so spent some time tinkering around with the realtionship parameters.</p>
<p>I ended up, effectively hard coding the join using the ON clause as follows:</p>
<pre>'StatusOption'=&gt; array(self::BELONGS_TO, 'Options', '', 'on' =&gt; 't.status=option_code AND option_name=\'Status\'',),</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/relations-using-a-non-primary-key/451/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; Further model validation</title>
		<link>http://sudwebdesign.com/yii-further-model-validation/439</link>
		<comments>http://sudwebdesign.com/yii-further-model-validation/439#comments</comments>
		<pubDate>Tue, 17 Jan 2012 11:23:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[custom validation]]></category>
		<category><![CDATA[rules]]></category>
		<category><![CDATA[validate]]></category>
		<category><![CDATA[validation]]></category>
		<category><![CDATA[validation rules]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=439</guid>
		<description><![CDATA[UPDATED 26-Jan-2012 ! A brief note today to add some more specific validation to your models.  As we all know &#8211; &#8220;rubbish in == rubbish out&#8221;, so let&#8217;s get that data nice and clean, right up front! public function rules() &#8230; <a href="http://sudwebdesign.com/yii-further-model-validation/439">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>UPDATED 26-Jan-2012 !</h2>
<p>A brief note today to add some more specific validation to your models.  As we all know &#8211; &#8220;rubbish in == rubbish out&#8221;, so let&#8217;s get that data nice and clean, right up front!</p>
<pre>public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
	                 <del>array('firstname, surname, address', 'match', 'pattern'=&gt;'/^[\w\-\_\'\,\.]+$/'),</del>
                         array('firstname, surname, address', 'match', 'pattern'=&gt;'/^[\\w\\-\\_\\'\\ \\,0-9\\p{L}]+$/u'),
                         array('startdate, enddate', 'date','format'=&gt;'d/m/yyyy', 'allowEmpty'=&gt;false),
                );
         }</pre>
<p>The address regex pattern is using a short-code \\w which matches all alphanumeric characters including diacritics (letters with accents etc..).  Added basic puctuation, hyphen(-), underscore(_), single quote (&#8216;),  comma(,) and full-stop/period (.) , 0-9 and lastly, if there is any chance that you might use multi-byte characters like utf-8, then the unicode point {L} matches any multi-byte letter. Note the <strong>/u</strong> at the end of the regex pattern which tells regex to use multi-byte matching. This combination should allow most european and amercian names and addresses like</p>
<address>O&#8217;hara</address>
<address>Smith-Klein</address>
<address>Cajó</address>
<address>King&#8217;s Cross St. Pancras</address>
<address>Béziers</address>
<address>and even åæßέ</address>
<p> It may/should even allow other multi-byte combinations, but I haven&#8217;t tested it on anything non-european yet!</p>
<p>&nbsp;</p>
<p>Please do add ideas for more validation rules below &#8230;</p>
<p>&nbsp;</p>
<p>further reading:  <a href="http://www.regular-expressions.info/unicode.html" rel="nofollow">Unicode Regex Patterns</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/yii-further-model-validation/439/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yii &#8211; How to customize a CGridView CbuttonColumn</title>
		<link>http://sudwebdesign.com/yii-how-to-customize-a-cgridview-cbuttoncolumn/431</link>
		<comments>http://sudwebdesign.com/yii-how-to-customize-a-cgridview-cbuttoncolumn/431#comments</comments>
		<pubDate>Thu, 12 Jan 2012 16:19:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=431</guid>
		<description><![CDATA[Update &#8211; Delete &#8211; View I&#8217;m sure you&#8217;ve already seen and used the basic buttons in a CGridView and maybe even used the template phrases to modify the behaviours array( 'class'=&#62;'CButtonColumn', 'template'=&#62;'{delete}{update}', 'buttons'=&#62;array( 'update'=&#62;array( 'url'=&#62;'$this-&#62;grid-&#62;controller-&#62;createUrl("/History/update", array("id"=&#62;$data-&#62;primaryKey,"asDialog"=&#62;1,"gridId"=&#62;$this-&#62;grid-&#62;id))', 'click'=&#62;'function(){$("#cru-frame").attr("src",$(this).attr("href")); $("#cru-dialog").dialog("open"); return false;}', &#8230; <a href="http://sudwebdesign.com/yii-how-to-customize-a-cgridview-cbuttoncolumn/431">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>Update &#8211; Delete &#8211; View</h2>
<p>I&#8217;m sure you&#8217;ve already seen and used the basic buttons in a CGridView and maybe even used the template phrases to modify the behaviours</p>
<pre>array(
     'class'=&gt;'CButtonColumn',
     'template'=&gt;'{delete}{update}',
     'buttons'=&gt;array(
               'update'=&gt;array(
                         'url'=&gt;'$this-&gt;grid-&gt;controller-&gt;createUrl("/History/update", array("id"=&gt;$data-&gt;primaryKey,"asDialog"=&gt;1,"gridId"=&gt;$this-&gt;grid-&gt;id))',
                         'click'=&gt;'function(){$("#cru-frame").attr("src",$(this).attr("href")); $("#cru-dialog").dialog("open");  return false;}',
                         ),
               'delete'=&gt;array(
                         'url'=&gt;'$this-&gt;grid-&gt;controller-&gt;createUrl("/History/delete", array("id"=&gt;$data-&gt;primaryKey,"asDialog"=&gt;1,"gridId"=&gt;$this-&gt;grid-&gt;id))',
                         ),
               ),</pre>
<p>&nbsp;</p>
<p>but sometimes we need to break out of this box and create custom buttons for slightly more exciting function like ordering with up and down buttons, or email, or add &#8230; and many more!</p>
<h2>Custom Buttons</h2>
<p>So you can add custom templates (or re-define existing ones) by using further properties of the CButtonColumn object as follows:-</p>
<pre>	array(
		'class'=&gt;'CButtonColumn',
		'template'=&gt;'{update}{add}{delete}',
		'buttons'=&gt;array(
			'update'=&gt;array(
					'url'=&gt;'$this-&gt;grid-&gt;controller-&gt;createUrl("/Extras/update", array("id"=&gt;$data-&gt;id,"asDialog"=&gt;1,"gridId"=&gt;$this-&gt;grid-&gt;id))',
					'click'=&gt;'function(){$("#cru-frame").attr("src",$(this).attr("href")); $("#cru-dialog").dialog("open");  return false;}',
						'visible'=&gt;'($data-&gt;id===null)?false:true;'
					),
			'add' =&gt; array(
					'label'=&gt;'Add',
					'imageUrl'=&gt;Yii::app()-&gt;request-&gt;baseUrl.'/css/gridViewStyle/images/gr-plus.png',
					'url'=&gt;'$this-&gt;grid-&gt;controller-&gt;createUrl("/Extras/create", array("eid"=&gt;$data-&gt;extras_id, "bid"=&gt;'.$model-&gt;id.', "asDialog"=&gt;1,"gridId"=&gt;$this-&gt;grid-&gt;id))',
					'click'=&gt;'function(){$("#cru-frame").attr("src",$(this).attr("href")); $("#cru-dialog").dialog("open");  return false;}',
					'visible'=&gt;'($data-&gt;id===null)?true:false;'
					),
			'delete'=&gt;array(
					'url'=&gt;'$this-&gt;grid-&gt;controller-&gt;createUrl("/Extras/delete", array("id"=&gt;$data-&gt;primaryKey,"asDialog"=&gt;1,"gridId"=&gt;$this-&gt;grid-&gt;id))',
					),

		),
	),</pre>
<p>You  may also notice that I&#8217;m using an alternative to full AJAX dialogs.  This method uses an iframe within a dialog widget and is much quicker and easier to setup.  You can find the full article by <a href="http://www.yiiframework.com/user/6785/">joblo </a>on the <a href="http://www.yiiframework.com/wiki/263/cgridview-update-create-records-in-a-cjuidialog/">Yii wiki</a></p>
<p>Further reading:-</p>
<p><a href="http://www.yiiframework.com/wiki/106/using-cbuttoncolumn-to-customize-buttons-in-cgridview/">http://www.yiiframework.com/wiki/106/using-cbuttoncolumn-to-customize-buttons-in-cgridview/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/yii-how-to-customize-a-cgridview-cbuttoncolumn/431/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Google Search results rolled out today</title>
		<link>http://sudwebdesign.com/new-google-search-results-rolled-out-today/428</link>
		<comments>http://sudwebdesign.com/new-google-search-results-rolled-out-today/428#comments</comments>
		<pubDate>Wed, 11 Jan 2012 06:54:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://sudwebdesign.com/?p=428</guid>
		<description><![CDATA[Today Google has rolled out it&#8217;s personalised search results world-wide. You will now see search results that include privately shared data on Google+ and Picasa &#8211; but don&#8217;t worry others can&#8217;t see it. However, it does highlight the need to &#8230; <a href="http://sudwebdesign.com/new-google-search-results-rolled-out-today/428">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Today Google has rolled out it&#8217;s personalised search results world-wide. You will now see search results that include privately shared data on Google+ and Picasa &#8211; but don&#8217;t worry others can&#8217;t see it.</p>
<p>However, it does highlight the need to be seen using Google+ to promote your business.  This is also the direction that it is rumoured Google is heading &#8230; that your site ranking will be scored on social media votes as much as (if not more than) external site links.</p>
<p>These changes highlight Google search&#8217;s integration with Google+, Google&#8217;s competitor to Facebook &#8211;  don&#8217;t confuse that with Google +1.  Google+ is heading towards 100 million users after only 18 months of being live.  It is forecasted that Google+ could have upwards of <strong>400 million users</strong> by the end of this year.</p>
<p>This isn&#8217;t a call to dump Facebook and rush across to Google+ but if you&#8217;re not yet using Google+ then you should think about it soon.</p>
<p>Start using it to promote your business, to publish material that is relevant to your industry and it will be seen by other Google+ users who are using Google search.  That could mean increased coverage =&gt; more business!</p>
<p>If you would like more information see this detailed article - <a href="http://searchengineland.com/googles-results-get-more-personal-with-search-plus-your-world-107285?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=feed-main">“Search Plus Your World”</a></p>
<p>Happy Google+ &#8216; ing &#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://sudwebdesign.com/new-google-search-results-rolled-out-today/428/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

