<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Projektant - Programista PHP, Python</title>
	
	<link>http://blog.adryjanek.eu</link>
	<description>Kamil Adryjanek - projektowanie aplikacji internetowych</description>
	<pubDate>Wed, 17 Feb 2010 19:07:38 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ProgramistaPhp" /><feedburner:info uri="programistaphp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Symfony and jQuery: sfWidgetFormJQueryMultiSelect ver 0.1</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/wmKAyQbg7uc/</link>
		<comments>http://blog.adryjanek.eu/2010/02/17/symfony-and-jquery-sfwidgetformjquerymultiselect-ver-01/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 19:07:38 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[Ext JS]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[News]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[sfForm]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=70</guid>
		<description><![CDATA[Recently i created nice and simple Symfony widget: sfWidgetFormJQueryMultiSelect. It&#8217;s really simple in use and implementation. I have used code written recently by Eric Hynds: jQuery MultiSelect Plugin w/ ThemeRoller Support and standard sfWidgetFormChoice.

As a result, i received sfWidgetFormJQueryMultiSelect.


&#60;?php

/**
 * sfWidgetFormJQueryMultiSelect represents a multi choice select widget.
 *
 * @package    symfony
 * [...]]]></description>
			<content:encoded><![CDATA[<p>Recently i created nice and simple Symfony widget: sfWidgetFormJQueryMultiSelect. It&#8217;s really simple in use and implementation. I have used code written recently by Eric Hynds: <a title="jQuery Multiselect" rel="external nofollow" href="http://www.erichynds.com/jquery/jquery-multiselect-plugin-with-themeroller-support/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.erichynds.com');" target="_blank">jQuery MultiSelect Plugin w/ ThemeRoller Support</a> and standard sfWidgetFormChoice.</p>
<p><span id="more-70"></span><br />
As a result, i received sfWidgetFormJQueryMultiSelect.</p>
<pre name="code" class="php">

&lt;?php

/**
 * sfWidgetFormJQueryMultiSelect represents a multi choice select widget.
 *
 * @package    symfony
 * @subpackage widget
 * @author     Kamil Adryjanek &lt;kamil.adryjanek@gmail.com&gt;

 */
class sfWidgetFormJQueryMultiSelect extends sfWidgetFormChoice
{
  /**
   * Constructor.
   *
   * Available options:
   *
   *  * choices:          An array of possible choices (required)
   *  * renderer_class:   The class to use instead of the default ones
   *  * renderer_options: The options to pass to the renderer constructor
   *  * renderer:         A renderer widget (overrides the expanded and renderer_options options)
   *                      The choices option must be: new sfCallable($thisWidgetInstance, &#039;getChoices&#039;)
   * @param array $options     An array of options
   * @param array $attributes  An array of default HTML attributes
   *
   * @see sfWidgetFormChoiceBase
   */

  protected function configure($options = array(), $attributes = array())
  {
    $this-&gt;addOption(&#039;config&#039;, &#039;{}&#039;);

    parent::configure($options, $attributes);

    $this-&gt;setOption(&#039;multiple&#039;, true);
    $this-&gt;setOption(&#039;expanded&#039;, true);
  }

  /**
   * @param  string $name        The element name
   * @param  string $value       The value selected in this widget
   * @param  array  $attributes  An array of HTML attributes to be merged with the default HTML attributes
   * @param  array  $errors      An array of errors for the field
   *
   * @return string An HTML tag string
   *
   * @see sfWidgetForm
   */
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
    return parent::render($name, $value = null, $attributes = array(), $errors = array()).
    	   sprintf(&lt;&lt;&lt;EOF
&lt;script type=&quot;text/javascript&quot;&gt;
  jQuery(document).ready(function() {
    jQuery(&quot;#%s&quot;).multiSelect(
      %s
   );
 });

&lt;/script&gt;
EOF
      ,
      $this-&gt;generateId($name),
      $this-&gt;getOption(&#039;config&#039;)
      );
  }
}
</pre>
<p><strong>How to use it</strong><br />
Include into your application neccessary JavaScripts (jQuery 1.4+ and jQuery UI required) and stylesheets: (for example view.yml):</p>
<pre name="code" class="xml">

  stylesheets:    [main.css, ui-lightness/jquery-ui-1.7.2.custom.css, jquery.multiselect.css]

  javascripts:    [jquery.js, jquery-ui.js, jquery.multiselect.js]
</pre>
<p>Then we need to create simple form and set our widgets:</p>
<pre name="code" class="php">

&lt;?php

class SimpleForm extends sfForm {

	public function configure() {

		$userChoices = array(&#039;John&#039;, &#039;Michael&#039;, &#039;Tom&#039;, &#039;Peter&#039;);

		$this-&gt;setWidgets(array(
			&#039;users&#039;	=&gt; new sfWidgetFormJQueryMultiSelect(array(
				&#039;choices&#039;	=&gt; $userChoices
			))
		));

		$this-&gt;setValidators(array(
			&#039;users&#039;	=&gt; new sfValidatorChoice(array(
				&#039;choices&#039;	=&gt; array_keys($userChoices)
			))
		));
	}
} 
</pre>
<p><strong>How does it work (look)</strong><br />
Form should now look similar to that:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2010/02/multi1.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2010/02/multi1.png" alt="MultiSelect Widget" title="multi1" width="500" height="243" class="alignnone size-full wp-image-71" /></a></p>
<p>Widget should work with Symfony 1.2.X - 1.4.X.</p>
<p>More information about jquery.multiselect plugin can be found <a title="jQuery Multiselect" rel="external nofollow" href="http://www.erichynds.com/jquery/jquery-multiselect-plugin-with-themeroller-support/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.erichynds.com');" target="_blank">on this page</a>.</p>
<p>In the near future I would like to create Symfony widget and put there some of my custom widgets (for example sfWidgetFormJQueryDateTime).</p>
<p>Enjoy</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/wmKAyQbg7uc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2010/02/17/symfony-and-jquery-sfwidgetformjquerymultiselect-ver-01/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2010/02/17/symfony-and-jquery-sfwidgetformjquerymultiselect-ver-01/</feedburner:origLink></item>
		<item>
		<title>ExtJS ans simple JavaScirpt Internationalization (i18n)</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/zt4cQEPtRWc/</link>
		<comments>http://blog.adryjanek.eu/2010/01/28/extjs-ans-simple-javascirpt-internationalization-i18n/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 18:39:55 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[Ext JS]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[extjs]]></category>

		<category><![CDATA[i18n]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=67</guid>
		<description><![CDATA[Lastely, building quite big Symfony and Ext.js application i was looking for simple way to make my application internationalized. I haven&#8217;t found any good solutions that would suits my needs. I found this on extjs forum: &#8216;The simplest way, perhaps, is to extract hardcoded strings to locale files. Then your framework just have to load [...]]]></description>
			<content:encoded><![CDATA[<p>Lastely, building quite big Symfony and Ext.js application i was looking for simple way to make my application internationalized. I haven&#8217;t found any good solutions that would suits my needs. I found this on extjs forum: &#8216;The simplest way, perhaps, is to extract hardcoded strings to locale files. Then your framework just have to load the selected language file together with YUI-ext.&#8221; I didn&#8217;t like that idea, i think it would be good for building some custom components but not for internationalize the whole application. I needed something quicker and less complicated.<br />
Than, i thought that i can write my own simple i18n mechanism - maybe there is better way (files can be generated on the server side), but this work for sure.<br />
<span id="more-67"></span><br />
I simple wrote custom JavaScript function __(string) and put it into one of my .js files:</p>
<pre name="code" class="javascript">

function __(string) {

	 if (typeof(i18n)!=&#039;undefined&#039; &amp;&amp; i18n[string]) {

		return i18n[string];
	}

	return string;
}
</pre>
<p>Then i attached another JavaScript file with translations object (before including __() function), for example we can call this file &#8220;pl_PL.js&#8221; and put there code:</p>
<pre name="code" class="javascript">

var i18n = {
	&#039;Country.&#039;							: &#039;Kraj&#039;,
	&#039;Description&#039;						: &#039;Opis&#039;,
	&#039;Population&#039;						: &#039;Populacja&#039;,
	&#039;Created at&#039;						: &#039;Data utworzenia&#039;,
	&#039;Symfony 1.2 and Ext.js example&#039;	: &#039;Przykład wykorzystania Symfony 1.2 i Ext.js &#039;
}
</pre>
<p>In our ExtJS components (or any other JavaScript code) we just simple call (example code from latest entry):</p>
<pre name="code" class="javascript">

	//columns structure
	var columns = [
		{id:&#039;name&#039;,header: __(&#039;Country&#039;), width: 160, sortable: true, dataIndex: &#039;name&#039;},
		{header: __(&#039;Description&#039;), width: 160, sortable: false, dataIndex: &#039;description&#039;},
		{header: __(&#039;Population&#039;), width: 160, sortable: true, dataIndex: &#039;population&#039;},
		{header: __(&#039;Created at&#039;), width: 100, sortable: true, dataIndex: &#039;created_at&#039;}
	];

	// gridPanel object
	var grid = new Ext.grid.GridPanel({
		title: __(&#039;Symfony 1.2 and Ext.js example&#039;),
		loadMask: true,   // mask panel when data is loading
		store: store,
		columns: columns,
		autoExpandColumn: &#039;name&#039;,
		height: 400,
		width: 600,
		renderTo: &#039;grid-example&#039;  // DOM element
	});

});
</pre>
<p>For me it&#8217;s simple, powerfull and really usefull.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/zt4cQEPtRWc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2010/01/28/extjs-ans-simple-javascirpt-internationalization-i18n/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2010/01/28/extjs-ans-simple-javascirpt-internationalization-i18n/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.4 and ExtJS - displaying data in GridPanel [english]</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/8VPmZfzQC68/</link>
		<comments>http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 22:00:25 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[extjs]]></category>

		<category><![CDATA[grid]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=62</guid>
		<description><![CDATA[Now when Symfony 1.4 and Dcotrine 1.2 time has come, i want to show you how easily we can use them with JavaScript framework ExtJs 3.0 - which is typically used to build advanced user interfaces. More information about that amazing library can be found on the main project website. In this post I would [...]]]></description>
			<content:encoded><![CDATA[<p>Now when Symfony 1.4 and Dcotrine 1.2 time has come, i want to show you how easily we can use them with JavaScript framework ExtJs 3.0 - which is typically used to build advanced user interfaces. More information about that amazing library can be found on the main project website. In this post I would like to demonstrate the capabilities of one of the components of this powerful framework - GridPanel. I will use most of the code presented in the previous entry, however, it will be updated to work correctly with the latest Symfony version.</p>
<p><span id="more-62"></span></p>
<p><strong>Configuration</strong></p>
<p>The necessary configuration for the tutorial:</p>
<ul>
<li>any server with PHP support at least version 5.2.4 + MySql database;</li>
<li>Symfony framework installed version 1.4.X (latest stable Symfony version is always recommended);</li>
<li>access to the command line;</li>
</ul>
<p><strong>At the begining</strong></p>
<p>After setting up the environment we need to create a new Symfony project, generate frontend application (if you use the sandbox is already generated) and a sample module, eg grid.<br />
To do so in the project directory from the command line should be performed sequentially:</p>
<pre name="code" class="xml">

symfony generate:project sfExtTest

symfony generate:app frontend

symfony generate:module frontend grid
</pre>
<p><strong>Connection to the database and test data</strong><br />
For our simple example, we could use static data created in JavaScript, howewer, i would like to show the flow of data between the client application, server and database (ExtJs - Symfony - MySql), so additional configuration is required.</p>
<p>You must configure the connection to database, create tables and load test data. The fallowing code is responsible for the above items (almost the same data have been used previously in this <a title="Symfony + jQuery Flexigrid" href="http://blog.adryjanek.eu/2009/02/01/symfony-jquery-flexigrid/"  target="_blank">tutorial</a>).</p>
<p>Configuring a database connection:</p>
<pre name="code" class="xml">

symfony configure:database mysql:host=localhost;dbname=your_db_name user pass
</pre>
<p>The structure of the test table:</p>
<pre name="code" class="xml">

country:
  actAs: [timestampable]
  columns:
    name:         string(50)
    description:  string(255)
    population:   integer(4)
</pre>
<p>Test data:</p>
<pre name="code" class="xml">

Country:
  Country_:
    name: &#039;Poland&#039;
    description: &#039;Description for Poland&#039;
    population: 38130302
  Country_2:
    name: &#039;Germany&#039;
    description: &#039;Description for Germany&#039;
    population: 82060000
  Country_3:
    name: &#039;Brazil&#039;
    description: &#039;Description for Brazil&#039;
    population: 192098152
  Country_4:
    name: &#039;USA&#039;
    description: &#039;Description for USA&#039;
    population: 308147000
  Country_5:
    name: &#039;Ireland&#039;
    description: &#039;Description for Ireland&#039;
    population: 6300000
  Country_6:
    name: &#039;Canada&#039;
    description: &#039;Description for Canada&#039;
    population: 33874000
  Country_7:
    name: &#039;India&#039;
    description: &#039;Description for India&#039;
    population: 1198003000
  Country_8:
    name: &#039;Italy&#039;
    description: &#039;Description for Italy&#039;
    population: 60200060
  Country_9:
    name: &#039;Spain&#039;
    description: &#039;Description for Spain&#039;
    population: 46661950
  Country_10:
    name: &#039;Portugal&#039;
    description: &#039;Description for Portugal&#039;
    population: 10707924
  Country_11:
    name: &#039;Argentina&#039;
    description: &#039;Description for Argentina&#039;
    population: 40482000
  Country_12:
    name: &#039;Estonia&#039;
    description: &#039;Description for Estonia&#039;
    population: 1340415
  Country_13:
    name: &#039;Bulgaria&#039;
    description: &#039;Description for Bulgaria&#039;
    population: 7606551
  Country_14:
    name: &#039;France&#039;
    description: &#039;Description for France&#039;
    population: 65073482
  Country_15:
    name: &#039;Belgium&#039;
    description: &#039;Description for Belgium&#039;
    population: 10665867
  Country_16:
    name: &#039;Austria&#039;
    description: &#039;Description for Austria&#039;
    population: 8356707
  Country_17:
    name: &#039;Australia&#039;
    description: &#039;Description for Australia&#039;
    population: 22076000
  Country_18:
    name: &#039;Japan&#039;
    description: &#039;Description for Japan&#039;
    population: 127590000
  Country_19:
    name: &#039;Russia&#039;
    description: &#039;Description for Russia&#039;
    population: 141909279
  Country_20:
    name: &#039;Slovakia&#039;
    description: &#039;Description for Slovakia&#039;
    population: 5379455
  Country_21:
    name: &#039;Ukraine&#039;
    description: &#039;Description for Ukraine&#039;
    population: 46011300
</pre>
<p>Now we need to run from command line sequentially:</p>
<pre name="code" class="xml">

  symfony doctrine:build --sql
  symfony doctrine:build --model
  symfony doctrine:build --db
  symfony doctrine:data-load
</pre>
<p><strong>ExtJS</strong><br />
Next step is to download the latest version (3,0) of ExtJs library from the project <a title="latest ExtJS library" href="http://www.extjs.com/products/extjs/download.php?dl=extjs3" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.extjs.com');"> official website</a> and unpack it to js/ext directory.</p>
<p>At this point we make changes to the configuration file: view.yml, so that the framework automatically attached the appropriate library js and css (changes should be made to the file: app/frontend/config/view.yml):</p>
<pre name="code" class="xml">

  stylesheets:
    - ../js/ext/resources/css/ext-all.css

  javascripts:
    - ext/adapter/ext/ext-base-debug.js
    - ext/ext-all-debug.js
</pre>
<p>It&#8217;s recommended to organize JavaScript code in separate JS file, but in this case, the code responsible for displaying the grid put in the index action view grid module.<br />
<div class="note"><div class="dropshadow"><div class="notehelp"> Please remember to remove the following code: $this-&gt;forward(&#8217;default&#8217;, &#8216;module&#8217;); from the actions.class.php file. </div></div></div></p>
<p>To be able to begin to work with the grid component we need to know at least the basis of its architecture and components. GridPanel essentially consists of 4 items:</p>
<ul>
<li><strong>Store</strong> - object responsible for data storing, including communication with server - in our case JsonStore;</li>
<li><strong>Column model</strong> - display configuration for each column (such as rendering options);</li>
<li><strong>View</strong> - special display settings;</li>
<li><strong>Selection model</strong> - optional component, is responsible for operations on columns (onClick, onSelect, onBeforeSelect) - i wiil try to show the use of this comopnent in a separate entry;</li>
</ul>
<p>To display the basic version of the grid we need the data, the configuration of columns that we want to display and configuration of the view (grid also accepts additional configuration options that are described in detail in the documentation).</p>
<p>The following code is responsible for all the above elements (file: apps/frontend/modules/grid/templates/indexSuccess.php):</p>
<pre name="code" class="php">

&lt;div id=&quot;grid-example&quot;&gt; &lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;

Ext.onReady(function() {

	// component responsible for connection to the server
	var store = new Ext.data.JsonStore({
		root: &#039;result&#039;,
		totalProperty: &#039;total&#039;, // total number of data
		idProperty: &#039;id&#039;,
		id: &#039;id&#039;,
		remoteSort: true,  // server-side sorting
		fields: [&#039;id&#039;, &#039;name&#039;, &#039;description&#039;, &#039;population&#039;, &#039;created_at&#039;],  // field structure
		url: &#039;grid/list&#039;,
		autoLoad: true  // autoloading
	});

	//columns structure
	var columns = [
		{id:&#039;name&#039;,header: &#039;Country&#039;, width: 160, sortable: true, dataIndex: &#039;name&#039;},
		{header: &#039;Description&#039;, width: 160, sortable: false, dataIndex: &#039;description&#039;},
		{header: &#039;Population&#039;, width: 160, sortable: true, dataIndex: &#039;population&#039;},
		{header: &#039;Created at&#039;, width: 100, sortable: true, dataIndex: &#039;created_at&#039;}
	];

	// gridPanel object
	var grid = new Ext.grid.GridPanel({
		title: &#039;Symfony 1.2 and Ext.js example&#039;,
		loadMask: true,   // mask panel when data is loading
		store: store,
		columns: columns,
		autoExpandColumn: &#039;name&#039;,
		height: 400,
		width: 600,
		renderTo: &#039;grid-example&#039;  // DOM element
	});

});

&lt;/script&gt;
</pre>
<p>To component can work properly we need to create additional action: &#8220;list&#8221; - for data processing (file: apps/frontend/modules/grid/actions/actions.class.php):</p>
<pre name="code" class="php">

&lt;?php

  public function executeList(sfWebRequest $request) {

	# some static data
	$limit = 15;
	$page = 1;

	# object responsible for paging
	$pager = new sfDoctrinePager(&#039;Country&#039;, $limit);

	$pager-&gt;setPage($page);
	$pager-&gt;init();

	$result = array();

	foreach($pager-&gt;getResults() as $country) {

		$result[] = $country-&gt;toArray();
	}

	# formatted data are returned to the grid
	return $this-&gt;renderText(json_encode(array(
		&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
		&#039;result&#039;	=&gt; $result
	)));
  }

?&gt;
</pre>
<p><div class="note"><div class="dropshadow"><div class="notetip">JSON (JavaScript Object Notation) is a data format used in applications based on the extjs framework. Access to data in JSON format is easier and faster with JavaScript than the level of access to the same data in XML format </div></div></div></p>
<p>At this point you can test the code: http://localhost/application-name/web/grid</p>
<p>We should see a grid similar to that shown in the figure below:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2009/12/grid1.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/12/grid1.png" alt="Sample grid" title="grid1" width="500" height="336" class="aligncenter size-full wp-image-65" /></a></p>
<p><strong>Support for paging and sorting</strong><br />
The current figure of the grid is quite inconvenient, displaying a couple of records on one list it not a problem, but when the database starts to grow, loading all the data and manipulate them, it becomes almost impossible.</p>
<p>PagingToolbar is a component responsible for paging on the ExtJs side. Its key element was defined earlier: store component. Responsible for the paging code is shown below:</p>
<pre name="code" class="php">

var paging = new Ext.PagingToolbar({
	pageSize: 10,  // items per page
	store: store,
	displayInfo: true,
	displayMsg: &#039;Displaying countries {0} - {1} of {2}&#039;,   // messages
	emptyMsg: &#039;Country list is empty&#039;
});

/ / small modification of the grid code
var grid = new Ext.grid.GridPanel({
	...
	bbar: paging,   // set the bottom panel
	...
});
</pre>
<p>To paging and sorting work properly, action &#8220;list&#8221; (in which we build the appropriate query based on request parameters) requires some modifications.</p>
<p><div class="note"><div class="dropshadow"><div class="notetip"> Each call to action in the grid causes a new request is created with the parameters: <strong>dir</strong> (sort direction ASC/DESC), <strong>limit</strong>, <strong>sort</strong> (name of the field), <strong>start</strong> (offset) </div></div></div></p>
<p>ExecuteList action, also requires modification - we need to add paging support and sorting by the selected column:</p>
<pre name="code" class="php">

&lt;?php

  public function executeList(sfWebRequest $request) {

	# data retrieved from the request
	$limit = $request-&gt;getParameter(&#039;limit&#039;, 10);
	$page = $request-&gt;hasParameter(&#039;start&#039;) ? $request-&gt;getParameter(&#039;start&#039;)/$limit+1 : 1;
	$dir = $request-&gt;getParameter(&#039;dir&#039;, &#039;ASC&#039;);
	$column = strtolower($request-&gt;getParameter(&#039;sort&#039;, &#039;name&#039;));

	# conditions for sorting
	$query = Doctrine_Query::create()-&gt;from(&#039;Country c&#039;);

	if (Doctrine::getTable(&#039;Country&#039;)-&gt;hasColumn($column)) {

		$query-&gt;orderBy(sprintf(&#039;c.%s %s&#039;, Doctrine::getTable(&#039;Country&#039;)-&gt;getFieldName($column), $dir));
	}

	# object responsible for paging
	$pager = new sfDoctrinePager(&#039;Country&#039;, $limit);

	# Pager query
	$pager-&gt;setQuery($query);
	$pager-&gt;setPage($page);
	$pager-&gt;init();

	$result = array();

	foreach($pager-&gt;getResults() as $country) {

		$result[] = $country-&gt;toArray();
	}

	# formatted data is returned to the grid
	return $this-&gt;renderText(json_encode(array(
		&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
		&#039;result&#039;	=&gt; $result,
		&#039;page&#039;		=&gt; $page
	)));
  }

?&gt;
</pre>
<p>Now we only need to refresh the page and verify that all changes have been properly marked - it should looks something like this:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2009/12/grid2.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/12/grid2.png" alt="Grid panel with paging and sorting" title="grid2" width="500" height="335" class="aligncenter size-full wp-image-66" /></a></p>
<p><div class="note"><div class="dropshadow"><div class="notetip">If not all the new items show up correctly it is recommended to clean the cache calling <strong>symfony cc command</strong> (alias for cache-clear). This type of operation should also be carried out, for example, after generating the classes of models or forms, installing plugins, especially when we change the configuration files that are stored in files with YML. </div></div></div></p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/8VPmZfzQC68" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english/</feedburner:origLink></item>
		<item>
		<title>NetDay Lublin #4</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/PT1RvByIZgk/</link>
		<comments>http://blog.adryjanek.eu/2009/11/18/netday-lublin-4/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 18:15:22 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[News]]></category>

		<category><![CDATA[Ogólne]]></category>

		<category><![CDATA[NetDay]]></category>

		<category><![CDATA[trendy]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=61</guid>
		<description><![CDATA[W sobotę 14 listopada w Lublinie, odbyło się 4 spotkanie branży internetowej z cyklu NetDay Lublin. Tym razem impreza odbyła się klubie &#8220;Kazik&#8221; przy ul. Nadbystrzyckiej 40a, co moim zdaniem było nietrafionym pomysłem. Wysoka frekwencja sprawiła, ze w Kaziku brakowalo miejsca i było bardzo gorąco. Ponadto częsć osób musiała śledzić prezentację na stojąco. Pub Johnny’s [...]]]></description>
			<content:encoded><![CDATA[<p>W sobotę 14 listopada w Lublinie, odbyło się 4 spotkanie branży internetowej z cyklu NetDay Lublin. Tym razem impreza odbyła się klubie &#8220;Kazik&#8221; przy ul. Nadbystrzyckiej 40a, co moim zdaniem było nietrafionym pomysłem. Wysoka frekwencja sprawiła, ze w Kaziku brakowalo miejsca i było bardzo gorąco. Ponadto częsć osób musiała śledzić prezentację na stojąco. Pub Johnny’s wypada pod tym względem zdecydowanie lepiej.</p>
<p><span id="more-61"></span></p>
<p>Same prezentacje zapowiadały się bardzo ciekawie. Po wystąpieniach, które miały miejsce w czerwcu (w szczególności przypadło mi do gustu bardzo ciekawe wystąpienie Pana Grzegorza Sławatyńskiego o targetowaniu behawioralnym), liczyłem na więcej. Nie będę się za bardzo rozpisywał - prawdopodobnie już niedługo pojawią się bardziej obszerne recenzje na oficjalnej stronie <a title="NetDay Lublin" href="http://netday.lublin.pl" onclick="javascript:pageTracker._trackPageview('/outbound/article/netday.lublin.pl');" target="_blank">NetDay</a>.</p>
<p>Tak w skrócie:</p>
<ul>
<li>na pierwszy ogień poszedł Googlemon. Tomasz Frelik raczej nie specjalnie zaciekawił zgromadzoną publiczność. Nie jestem specjalnie zaznajomiony z SEO, ale nawet dla mnie rzeczy o których mówił Tomek były oczywiste. Osobiście odebrałem to wystąpienie raczej jako reklamę niezbyt dopracowanego serwisu (nigdy wcześniej o Nim nie słyszałem). Sam pomysł jest ciekawy - jednakże jego autor musi nad Nim jeszce popracować - jak sam zresztą przyznaje.</li>
<li>następnie zaprezentował się Jarosław Bielecki z Mint Media. Wystąpienie zdecydowanie ciekawsze i dużo lepiej przemyślane. MintMedia to nowo powstała sieć internetowa świadcząca usługi w zakresie reklamy internetowej. Prezentacja opierała się na wyjaśnieniu zasad działania tego typu reklamy i możliwości jakie oferuje zarówno potencjalnym klientom, jaki i współpracującym wydawcom.</li>
<li>wystąpienie Michała Krawczyka, osoby odpowiedzialnej za marketing internetowy UM Lublin, wzbudziło najwięcej emocji. Prezentacja dotyczyła prowadzonych ostatnio kampanii promujących Lublin w sieci. Ciekawe wystąpienie wywołało żywą dyskusję wśród zgromadzonych. Wprawdzie o wspomnianych reklamach (z wyjątkiem jednej: &#8220;Przeżyj studia. Studiuj w Lublinie&#8221;) nigdy wcześniej nie słyszałem, cieszyć może fakt, że Lublin w końcu w sieci zaistniał. W tym momencie, jak dowiadujemy się z od Pana Michała, priorytetem jest reklama Lublina poza granicami naszego miasta, jednakże w przyszłorocznym budżecie nie zabraknie miejsca dla promocji inicjatyw lokalnych.</li>
</ul>
<p>Niestety z przyczyn ode mnie niezależnych nie mogłem uczestniczyć w pozostałych wystąpieniach.</p>
<p>Podsumowując, 4 spotkanie lubelskiej branży internetowej pozostawiło pewien niedosyt. Na przyszłość przydałoby się więcej wystąpień dotyczących konkretnych zagadnień związanych np z marketingiem w wyszukiwarkach, e-commerce czy chociażby o trendach wśród developerów. Uważam, że ciekawym i przyszłosciowym pomysłem byłoby utworzenie swojego rodzaju kategorii/dziedzin do których moznaby zapraszac prelegentów. Spotkania napewno byłby ciekawsze i mniej monotematyczne.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/PT1RvByIZgk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/11/18/netday-lublin-4/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/11/18/netday-lublin-4/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.2 i ExtJS - wyświetlanie danych w gridzie</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/dHmKZ3368yA/</link>
		<comments>http://blog.adryjanek.eu/2009/10/21/symfony-12-i-extjs-wyswietlanie-danych-w-gridzie/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 20:52:06 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[extjs]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=49</guid>
		<description><![CDATA[Ostatnio miałem przyjemność poznać i przetestować możliwości frameworka JavaScript: ExtJS. Jest to biblioteka przeznaczona do budowania zaawansowanych interfejsów użytkownika, w szczególności paneli administracyjnych.
W niniejszym wpisie chciałbym na prostym przykładzie zademonstrować możliwości jednego z komponentów tego potężnego frameworka - GridPanel . Jeszcze nie wiem czy będzie to część większego cyklu kursów o extjs i czy pojawi [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio miałem przyjemność poznać i przetestować możliwości frameworka JavaScript: ExtJS. Jest to biblioteka przeznaczona do budowania zaawansowanych interfejsów użytkownika, w szczególności paneli administracyjnych.</p>
<p>W niniejszym wpisie chciałbym na prostym przykładzie zademonstrować możliwości jednego z komponentów tego potężnego frameworka - GridPanel . Jeszcze nie wiem czy będzie to część większego cyklu kursów o extjs i <del datetime="2009-12-21T06:30:19+00:00">czy pojawi się on także w wersji angielskiej</del> (<strong><a title="Symfony 1.4 and ExtJS - displaying data in GridPanel" href="http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english/" >wersja angielska</a> - dodatkowo zaktualizowana dla Symfony 1.4 i Doctrine</strong>), ale narazie w planie mam wpisy dotyczące integracji z zaawansowanym systemem filtrów (ExtJS filter plugin) i dodawania/edytowania elementów do grida za pomocą modalnych okien - o ile oczywiście tematyka tego wpisu spotka się z zainteresowaniem.</p>
<p><span id="more-49"></span></p>
<p><strong>Konfiguracja</strong></p>
<p>Niezbędna konfiguracja dla tutoriala:</p>
<ul>
<li>dowolny serwer z obsługa PHP w wersji co najmniej 5.2.4 + baza danych  MySql;</li>
<li>zainstalowany framework Symfony w wersji 1.2.X (nic nie stoi na przeszkodzie by wypróbować sf 1.3) lub ewentualnie <a title="Symfony sandbox" href="http://www.symfony-project.org/get/sf_sandbox_1_2.zip" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');">sandbox</a> do pobrania (piaskownica Symfony- wstępnie skonfigurowany framework gotowy do pracy od zaraz);</li>
<li>dostęp do wiersza poleceń;</li>
</ul>
<p><strong>Rozpoczynamy prace</strong><br />
Mając tak przygotowane środowisko należy utworzyć nowy projekt, wygenerować aplikacje frontendu (w przypadku korzystania z piaskownicy jest już wygenerowana) i przykładowy moduł, np: grid. By tego dokonać w katalogu projektu z wiersza poleceń należy wykonać kolejno:</p>
<pre name="code" class="xml">

symfony generate:project sfExtTest

symfony generate:app frontend

symfony generate:module grid
</pre>
<p><strong>Połączenie z bazą danych i dane testowe</strong><br />
Dla naszego prostego przykładu moglibyśmy wykorzystać statyczne dane utworzone w JavaScript, jednakże chce pokazać przepływ danych między aplikacją klienta, a serwerem i bazą danych (między framewrokiem ExtJS, a Symfony i bazą danych), także niezbędna będzie dodatkowa konfiguracja.</p>
<p>Należy skonfigurować połączenie z bazą danych, utworzyć testowe tabele i wczytać do nich dane testowe. Poniższy kod odpowiada za wymienione powyżej elementy (poniższe dane zostały już wcześnie wykorzystane w <a title="Symfony + jQuery Flexigrid" href="http://blog.adryjanek.eu/2009/02/01/symfony-jquery-flexigrid/"  target="_blank">tutorialu</a>).</p>
<p>Konfiguracja połączenia z bazą danych:</p>
<pre name="code" class="xml">

symfony configure:database “mysql:host=localhost;dbname=twojaBazaDanych” uzytkownik haslo
</pre>
<p>Struktura tabeli testowej:</p>
<pre name="code" class="xml">

propel:
  country:
    _attributes: { phpName: Country }
    id:
    name: varchar(50)
    description: varchar(255)
    created_at:
</pre>
<p>Dane testowe:</p>
<pre name="code" class="xml">

Country:
  Country_1:
    name: &#039;Poland&#039;
    description: &#039;Description for Poland&#039;
  Country_2:
    name: &#039;Germany&#039;
    description: &#039;Description for Germany&#039;
  Country_3:
    name: &#039;Brazil&#039;
    description: &#039;Description for Brazil&#039;
  Country_4:
    name: &#039;USA&#039;
    description: &#039;Description for USA&#039;
  Country_5:
    name: &#039;Ireland&#039;
    description: &#039;Description for Ireland&#039;
  Country_6:
    name: &#039;Canada&#039;
    description: &#039;Description for Canada&#039;
  Country_7:
    name: &#039;India&#039;
    description: &#039;Description for India&#039;
  Country_8:
    name: &#039;Italy&#039;
    description: &#039;Description for Italy&#039;
  Country_9:
    name: &#039;Spain&#039;
    description: &#039;Description for Spain&#039;
  Country_10:
    name: &#039;Portugal&#039;
    description: &#039;Description for Portugal&#039;
  Country_11:
    name: &#039;Argentina&#039;
    description: &#039;Description for Argentina&#039;
  Country_12:
    name: &#039;Estonia&#039;
    description: &#039;Description for Estonia&#039;
  Country_13:
    name: &#039;Bulgaria&#039;
    description: &#039;Description for Bulgaria&#039;
  Country_14:
    name: &#039;France&#039;
    description: &#039;Description for France&#039;
  Country_15:
    name: &#039;Belgium&#039;
    description: &#039;Description for Belgium&#039;
  Country_16:
    name: &#039;Austria&#039;
    description: &#039;Description for Austria&#039;
  Country_17:
    name: &#039;Australia&#039;
    description: &#039;Description for Australia&#039;
  Country_18:
    name: &#039;Japan&#039;
    description: &#039;Description for Japan&#039;
  Country_19:
    name: &#039;Russia&#039;
    description: &#039;Description for Russia&#039;
  Country_20:
    name: &#039;Slovakia&#039;
    description: &#039;Description for Slovakia&#039;
  Country_21:
    name: &#039;Ireland&#039;
    description: &#039;Description for Ireland&#039;
</pre>
<p>Teraz wystarczy z poziomu lini komend wywołać kolejno:</p>
<pre name="code" class="xml">

  symfony propel:build-sql
  symfony propel:build-model
  symfony propel:insert-sql
  symfony propel:data-load
</pre>
<p><strong>ExtJS</strong><br />
Następnym krokiem jest pobranie najnowszej wersji (3,0) biblioteki ExtJs. Całość ściągamy z <a title="pobierz najnowszą wersję ExtJS" href="http://www.extjs.com/products/extjs/download.php?dl=extjs3" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.extjs.com');">oficjalnej strony EXTa</a> i wypakowujemy do katalogu ext.</p>
<p>W tym momencie warto dokonać konfiguracji pliku view.yml, tak by framework automatycznie załączył odpowiednie biblioteki js i css (zmian należy dokonoać w pliku app/frontend/config/view.yml):</p>
<pre name="code" class="xml">

stylesheets:
- ../js/ext/resources/css/ext-all.css

javascripts:
- ext/adapter/ext/ext-base-debug.js
- ext/ext-all-debug.js
</pre>
<p>Zalecane jest by kod JavaScript organizować w osobnych plikach JS, jednakże w tym wypadku kod odpowiedzialny za wyświetlanie grida umieścimy w widoku akcji index modułu Grid.<br />
<div class="note"><div class="dropshadow"><div class="notehelp"> Należy pamiętać by usunąć wcześniej z akcji kod odpowiedzialny za przekierowanie do domyślnego modułu, w moim przypadku $this-&gt;forward(&#8217;default&#8217;, &#8216;module&#8217;); </div></div></div></p>
<p>By móc w ogóle przystąpić do pracy z komponentem grida trzeba poznać przynajmniej podstawy jego budowy i elementy składowe. Zasadniczo na GridPanel składa się 4 elementy:</p>
<ul>
<li><strong>Store</strong> - obiekt odpowiedzialny za przechowywanie danych, w tym komunikację z serwerem - w naszym przypadku JsonStore;</li>
<li><strong>Column model</strong> - konfiguracja wyświetlania poszczególnych kolumn (m.in. opcje renderowania);</li>
<li><strong>View</strong> - specyficzne ustawienia efektów wyświetlania;</li>
<li><strong>Selection model</strong> - element nieobowiązkowy, odpowiada za operacje na kolumnach (zaznaczanie, pobieranie zaznaczonych) - postaram się pokazać zastosowanie tego komponentu w osobnym wpisie;</li>
</ul>
<p>Także aby wyświetlić podstawową wersję grida potrzebujemy danych, konfiguracji kolumn, które chcemy wyświetlić i konfiguracji widoku (grid przyjmuje również dodatkowe opcje konfiguracyjne opisane szczegółowo w dokumentacji).</p>
<p>Poniższy kod odpowiada za wszystkie wyżej wymienione elementy (kod pliku: apps/frontend/modules/grid/templates/indexSuccess.php):</p>
<pre name="code" class="php">

&lt;div id=&quot;grid-example&quot;&gt; &lt;/div&gt;

&lt;?php javascript_tag(); ?&gt;

Ext.onReady(function() {

	// komponent odpowiadający za połączenie z serwerem
 	var store = new Ext.data.JsonStore({
		root: &#039;result&#039;,
		totalProperty: &#039;total&#039;, //całwkoita ilość zwracanych danych
		idProperty: &#039;id&#039;,
		id: &#039;id&#039;,
		remoteSort: true,  // sortowanie po stronei serwera
		fields: [&#039;id&#039;, &#039;name&#039;, &#039;description&#039;, &#039;created_at&#039;],  // struktura zwracanych elementów
		url: &#039;grid/list&#039;,  // adres url na serwerze
		autoLoad: true  // automatyczne ładowanie danych
	});

	//struktura kolumn
	var columns = [
            {id:&#039;name&#039;,header: &#039;Państwo&#039;, width: 160, sortable: true, dataIndex: &#039;name&#039;},
            {header: &#039;Opis&#039;, width: 160, sortable: false, dataIndex: &#039;description&#039;},
            {header: &#039;Data utworzenia&#039;, width: 100, sortable: true, dataIndex: &#039;created_at&#039;}
        ];

    // obiekt grida
    var grid = new Ext.grid.GridPanel({
    	title: &#039;Symfony 1.2 and Ext.js example&#039;,
    	loadMask: true,   //maskowanie ładowania danych
        store: store,
        columns: columns,
        autoExpandColumn: &#039;name&#039;,
        height: 400,
        width: 600,
        renderTo: &#039;grid-example&#039;  // element DOM do którego ma być załadowany grid
    });

});

&lt;?php end_javascript_tag(); ?&gt;
</pre>
<p>By całość mogła poprawnie działać nalezy utowrzyć dodatkową akcje &#8220;list&#8221;, z której komponent store będzie pobierał dane do grida (kod pliku: apps/frontend/modules/grid/actions/actions.class.php):</p>
<pre name="code" class="php">

&lt;?php

   public function executeList(sfWebRequest $request) {

  	 // tymczasowe dane ustawione na sztywno
  	$limit = 15;
    $page = 1;

     // pomocniczy obiekt odpowiedzialny za stronicowanie
  	$pager = new sfPropelPager(&#039;Country&#039;, $limit);

    $pager-&gt;setPage($page);
    $pager-&gt;init();

    $result = array();

    foreach($pager-&gt;getResults() as $country) {

    	$result[] = $country-&gt;toArray(BasePeer::TYPE_FIELDNAME);
    }

     // sformatowane dane są zwracane do grida
    return $this-&gt;renderText(json_encode(array(
    	&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
    	&#039;result&#039;	=&gt; $result
    )));
  }

?&gt;
</pre>
<p><div class="note"><div class="dropshadow"><div class="notetip">JSON (JavaScript Object Notation) jest podstawowym formatem danych używanym w aplikacjach opartych o framework ExtJS. Dostęp do danych w formacie JSON jest łatwiejszy i szybszy z poziomu języka JavaScript niż dostęp do tych samych danych w formacie XML </div></div></div></p>
<p>W tym momencie można sprawdzić działanie kodu wywołując w przeglądarce adres:<br />
http://localhost/nazwa-aplikacji/web/grid</p>
<p>Powinniśmy ujrzeć grida podobnego do tego przedstawionego na rysunku poniżej:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2009/10/j1.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/10/j1.png" alt="" title="j1" width="500" height="332" class="aligncenter size-full wp-image-56" /></a></p>
<p><strong>Obsługa stronicowania i sortowania</strong></p>
<p>Obecna postac grida jest dość niewygodna, o ile w przypadku kilkunastu rekordów wyświetlanie ich na jednej stronie nie jest zbyt kłopotliwe, to w momencie gdy baza zacznie się rozrastać ładowanie wszystkich danych i operowanie na nich staje się niemal niemożliwe.</p>
<p>Za stronicowanie po stronie ExtJS odpowiada component: PagingToolbar. Jego kluczowym elementem jest zdefiniowany wcześniej komponent store. Kod odpowiedzialny za stronicowanie widoczny jest poniżej: </p>
<pre name="code" class="php">

	paging = new Ext.PagingToolbar({
		pageSize: 10,  // ilość elementów
		store: store,  // obiekt magazynujący dane
		displayInfo: true,  //wyśweitlanie dodatkowych informacji
		displayMsg: &#039;Wyświetlanie państw {0} - {1} z {2}&#039;,   // komunikaty
		emptyMsg: &quot;Lista państw jest pusta&quot;  

	});

         //małą modyfikacja kodu grida
	var grid = new Ext.grid.GridPanel({
        	...
		bbar: paging,   // ustawiamy dolny panel grida
		...
	});
</pre>
<p>By stronicowanie i sortowanie działało prawidłowo modyfikacji wymaga akcja list, w której musimy zbudować odpowiednie zapytanie na podstawie parametrów żądania. </p>
<p><div class="note"><div class="dropshadow"><div class="notetip"> Wywołanie akcji sortowania lub stronicowania w gridzie powoduje, ze tworzone jest nowe żądanie pobrania danych z akcji list z parametrami: <strong>dir</strong> (kierunek sortowania ASC/DESC), <strong>limit</strong>, <strong>sort</strong> (nazwa pola po którym sortujemy), <strong>start</strong>	(offset) </div></div></div></p>
<p>Modyfikacji wymaga też sama akcja executeList - musimy dodać do Niej obsługę stronicowania i sortowania po wybranej kolumnie:</p>
<pre name="code" class="php">

&lt;?php

  public function executeList(sfWebRequest $request) {

  	 // dane pobierane z żądania
  	$limit = $request-&gt;getParameter(&#039;limit&#039;, 10);
    $page = $request-&gt;hasParameter(&#039;start&#039;) ? $request-&gt;getParameter(&#039;start&#039;)/$limit+1 : 1;
    $dir = $request-&gt;getParameter(&#039;dir&#039;, &#039;asc&#039;);
    $column = strtolower($request-&gt;getParameter(&#039;sort&#039;, &#039;name&#039;));

     # warunki dla sortowania
    $c = new Criteria();
   	if (in_array($column, CountryPeer::getFieldNames(BasePeer::TYPE_FIELDNAME))) {

   		$column = CountryPeer::translateFieldName($column, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME);
   		if ($dir == &quot;ASC&quot;) {

   			$c-&gt;addAscendingOrderByColumn($column);
   		} else {

   			$c-&gt;addDescendingOrderByColumn($column);
   		}
   	}

     # pomocniczy obiekt odpowiedzialny za stronicowanie
  	$pager = new sfPropelPager(&#039;Country&#039;, $limit);

  	 # kryteria dla pagera
  	$pager-&gt;setCriteria($c);
    $pager-&gt;setPage($page);
    $pager-&gt;init();

    $result = array();

    foreach($pager-&gt;getResults() as $country) {

    	$result[] = $country-&gt;toArray(BasePeer::TYPE_FIELDNAME);
    }

     # sformatowane dane są zwracane do grida
    return $this-&gt;renderText(json_encode(array(
    	&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
    	&#039;result&#039;	=&gt; $result,
    	&#039;page&#039;		=&gt; $page
    )));
  }

?&gt;
</pre>
<p>Teraz wystarczy tylko odświeżyć stronę i sprawdzić czy wszystkie zmiany zostały poprawnie naniesione - całość powinna wyglądać mniej więcej tak:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2009/10/f2.jpg'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/10/f2.jpg" alt="" title="Widok grida" width="500" height="335" class="aligncenter size-full wp-image-57" /></a></p>
<p><div class="note"><div class="dropshadow"><div class="notetip">W przypadku gdy nie wszystkie nowe elementy wyświetlają się poprawnie zalecane jest czyszczenie cache komendą <strong>symfony cc</strong> (alias dla clear-cache). Tego typu operację należy również przeprowadzić w przypadku np: generowania klas modeli czy formularzy, instalacji pluginów, a w szczególności gdy zmieniamy pliki konfiguracyjne zapisane w plikach z rozszerzeniem YML. </div></div></div></p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/dHmKZ3368yA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/10/21/symfony-12-i-extjs-wyswietlanie-danych-w-gridzie/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/10/21/symfony-12-i-extjs-wyswietlanie-danych-w-gridzie/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.3 Web Application Development - my review</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/AcTTvBlBM3k/</link>
		<comments>http://blog.adryjanek.eu/2009/10/16/symfony-13-web-application-development-my-review/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 22:04:02 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[projektowanie aplikacji]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=55</guid>
		<description><![CDATA[Last week I received my copy of new Symfony book: Symfony 1.3 Web Application Development. What is really interesting about this book that it has been released even before Symfony 1.3 Alpha version. The book gives an overview of Symfony Framework and covers almost each stage of application developing process: from creating the application structure [...]]]></description>
			<content:encoded><![CDATA[<p><a title="Symfony 1.3 Web Application Development" href="http://www.packtpub.com/symfony-1-3-web-application-development/book" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.packtpub.com');" target="_blank"><img class="alignleft size-full wp-image-58" style="border: 1px solid black; margin: 5px; float: left;" title="symfony-13-web-application-development" src="http://blog.adryjanek.eu/wp-content/uploads/2009/10/symfony-13-web-application-development.png" alt="symfony-13-web-application-development" width="113" height="139" /></a>Last week I received my copy of new Symfony book: Symfony 1.3 Web Application Development. What is really interesting about this book that it has been released even before Symfony 1.3 Alpha version. The book gives an overview of Symfony Framework and covers almost each stage of application developing process: from creating the application structure and database schema, to creating the Admin Area, performance optimization and deployment. As we know the  best way to learn is to learn by example and this book describies how to build milkshake shop quite well.</p>
<p><span id="more-55"></span></p>
<p>The Good:</p>
<ul>
<li>dealing with forms: how to create, customize and submit the form. Also shows how to use sfExtraFormPlugins widgets for JavaScript/Ajax integration;</li>
<li>plugins: installing and creating new plugins;</li>
<li>security: dealing with user credentials;</li>
<li>creating custom form formatters;</li>
<li>creating and customizing admin area;</li>
<li>internationalization: explained really well;</li>
<li>delopoyment: preparing and transferring application to server;</li>
</ul>
<p>The Bad:</p>
<ul>
<li>dealing with e-mail: intergartion with SwiftMailer in sf 1.3;</li>
<li>it would be nice to see Zend Framework integration in practice;</li>
<li>starting project with sf 1.3 and Propel - i really like Propel but sf 1.3 has much more better support for Doctrine;</li>
<li>nothing about new installer option;</li>
<li>nothing about updated form methods - useFields;</li>
<li>some irritating inline css;</li>
</ul>
<p>What i really like about this book:</p>
<ul>
<li>dealing with Symfony and memcache;</li>
<li>optimization: templates caching</li>
</ul>
<p>For me, it&#8217;s not enough. I think the Jobeet tutorial is better introduction to Symfony then Milkshake shop. So if we want to be introduced to all new Symfony 1.3 features - we would have to wait for some book upgrade or read the Symfony 1.3 documentation. My rate is 3 out of 5, i can recommend this book for beginners.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/AcTTvBlBM3k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/10/16/symfony-13-web-application-development-my-review/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/10/16/symfony-13-web-application-development-my-review/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.3</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/Ilii0rMQsZU/</link>
		<comments>http://blog.adryjanek.eu/2009/09/29/symfony-13/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 18:11:09 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[News]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[Doctrine]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=53</guid>
		<description><![CDATA[W ubiegłym tygodniu ukazała się wersja 1.3 alpha znakomitego frameworka Symfony. Z pewnością nie uświadczymy rewolucji podobnej do tej w momencie ukazania się sf 1.1 i 1.2, jednak liczne drobne zmiany jakie wprowadzono powinny dość znacząco usprawnić naszą prace - pełna lista zmian dostępna jest tutaj. Wersja 1.3 podobnie jak 1.1 ma być jedynie wersją [...]]]></description>
			<content:encoded><![CDATA[<p>W ubiegłym tygodniu ukazała się wersja 1.3 alpha znakomitego frameworka Symfony. Z pewnością nie uświadczymy rewolucji podobnej do tej w momencie ukazania się sf 1.1 i 1.2, jednak liczne drobne zmiany jakie wprowadzono powinny dość znacząco usprawnić naszą prace - pełna lista zmian dostępna jest <a title="Lista zmian w wersji 1.3" href="http://www.symfony-project.org/tutorial/1_3/en/whats-new" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');" target="_blank">tutaj</a>. Wersja 1.3 podobnie jak 1.1 ma być jedynie wersją przejściową do 1.4, która ma się ukazać dopiero w 2010 roku i która będzie wspierana do 2013.</p>
<p><span id="more-53"></span><br />
Poniżej krótka lista najważniejszych wg mnie zmian:</p>
<p>- E-mail. Dodano domyślny system odpowiadający za wysyłanie e-maili oparty o <a title="SwiftMailer" href="http://swiftmailer.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/swiftmailer.org');">SwiftMailer</a> 4.1. Nie miałem okazji testować tego mailera, także nie mogę podać żadnych konkretnych argumentów &#8220;za&#8221;, bądź &#8220;przeciw&#8221;. Wiem natomiast, że nowym Project Managerem tego projektu został Fabien Potencier, także o jego dalszy rozwój i wsparcie możemy być spokojni. Do tej pory w swoich projektach z powodzeniem wykorzystywałem Zend_Mail, a SwiftMiailera postaram się przetestować przy najbliższej okazji. Poniżej przykład wykorzystania zintergorwanego z Symfony SwiftMailera:</p>
<pre name="code" class="php">

&lt;?php

$message = $this-&gt;getMailer() -&gt;compose(&#039;od@przyklad.pl&#039;, &#039;do@przyklad.pl&#039;, &#039;Temat wiadomości&#039;, &#039;Treść&#039;)-&gt;attach(Swift_Attachment::fromPath(&#039;/sciezka/do/pliku&#039;));

$this-&gt;getMailer()-&gt;send($message);

?&gt;
</pre>
<p>- Doctrine jako domyślny ORM. Pomimo tego, że pomału przekonuję się do tego ORMa, w większych projektach wciąż zostaje przy Propelu - budowanie zapytań z wykorzystaniem obiektów Criteria bardziej przypadło mi do gustu. Wg zapowiedzi wsparcie dla Propela ma się zakończyć wraz z pojawieniem się sf 2.0, jednakże ostatnio przewodzenie na projektem Propel objął François Zaninotto (były pracownik Sensio, autor wielu pluginów i części dokumentacji), co mam nadzieje zaowocuje reaktywacją projektu (wersja 1.4 ma ukazać się w  październiku). Wracając do samego Doctrine - dodano nowe opcje dla definiowania struktury bazy danych w pliku YAML, a także nowe komendy dla generatorów (m.in: doctrine:build, doctrine:reload-data, doctrine:create-model-tables, doctrine:delete-model-tables, doctrine:clean-model-files).</p>
<p>- Formularze. Przede wszystkim dodano metodę useFields (mój odopwiedniki unsetAllExcept, przykład poniżej), klasy: BaseForm (klasa nadrzędna dla wszystkich formularzy) i sfFormSymfony (przydatna przy implementacji zdarzeń na formularzach). Ponadto dodano brakujące metody takie jak: setDefault(), setLabel(), setIdFormat(), setHidden() dla komponentów wykorzystywanych w formularzach.</p>
<pre name="code" class="php">

&lt;?php
  class UserForm extends BaseUserForm
  {
    public function configure()
    {
      $this-&gt;useFields(array(
        &#039;name&#039;,
        &#039;surname&#039;,
        &#039;email&#039;
      ));
    }
  }

?&gt;
</pre>
<p>- innym ciekawym dodatkiem do nowej wersji sf jest możliwość tworzenia własnego skryptu instalatora. By tego dokonać należy podczas tworzenia nowego projektu użyć opcji &#8211;installer i zadać odpowiedni parametr skryptu (przykład poniżej).</p>
<p>Z poziomu wiersza poleceń:</p>
<pre name="code" class="php">

    php symfony generate:project --installer=custom_installer.php
</pre>
<p>Przykładowy skrypt instalatora (na podstawie &#8220;Symfony 1.3 + Doctrine 1.2&#8243;):</p>
<pre name="code" class="php">

  if (!$this-&gt;askConfirmation(&#039;Czy jestes pewien, ze chcesz rozpoczac instalacje?&#039;)) {

    return ;
  }

  $this-&gt;installDir(dirname(__FILE__) . &#039;/skeleton&#039;);

  $this-&gt;runTask(&#039;plugin:publish-assets&#039;);

  $validator = new sfValidatorEmail(array(), array(&#039;invalid&#039; =&gt; &#039;Podano nie prawidlowy adres e-mail&#039;));

  $email = $this-&gt;askAndValidate(&#039;Prosze podac swoj adres e-mail:&#039;, $validator);

  $this-&gt;runTask(&#039;configure:author&#039;, sprintf(&quot;&#039;%s&#039;&quot;, $email));

  $secret = $this-&gt;ask(&#039;Prosze podac unikalny ciag znakow dla ochrony CSRF:&#039;);

  $this-&gt;runTask(&#039;generate:app&#039;, &#039;frontend --escaping-strategy=true --csrf-secret=&#039; . $secret);

  $this-&gt;runTask(&#039;plugin:install&#039;, &#039;sfDoctrineGuardPlugin&#039;);

  $this-&gt;reloadTasks();

  $this-&gt;runTask(&#039;guard:create-user&#039;, &#039;kamil haslo&#039;);

  $this-&gt;runTask(&#039;clear:cache&#039;);
</pre>
<p>Migracja do nowej wersji nie powinna przysporzyć problemów - instrukcja dostępna jest na <a title="migracja do sf 1.3" href="http://www.symfony-project.org/tutorial/1_3/en/upgrade" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');">stronie projektu</a>.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/Ilii0rMQsZU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/09/29/symfony-13/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/09/29/symfony-13/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.2 + admin generator + jquery layout plugin</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/nsXrNWEXdII/</link>
		<comments>http://blog.adryjanek.eu/2009/08/03/symfony-12-admin-generator-jquery-layout-plugin/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 18:38:25 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[admin generator]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=47</guid>
		<description><![CDATA[After a couple of weeks i decided to write another post about Symfony 1.2 and jQuery. This simple tutorial shows you how integrate jQuery layout plugin, jQuery accordion widget for navigation and Symfony admin generator.
Symfony offers nice and powerfull admin generator feature. After rewriting in version 1.2 it uses form and filter framework which makes [...]]]></description>
			<content:encoded><![CDATA[<p>After a couple of weeks i decided to write another post about Symfony 1.2 and jQuery. This simple tutorial shows you how integrate jQuery layout plugin, jQuery accordion widget for navigation and Symfony admin generator.<br />
Symfony offers nice and powerfull admin generator feature. After rewriting in version 1.2 it uses form and filter framework which makes it really easy and customizable. For more details you need to check <a href="http://www.symfony-project.org/book/1_2/14-Generators" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');" target="_blank"> admin generator documentation </a>.</p>
<p>&#8220;JQuery Layout plug-in was inspired by the extJS border-layout, and recreates that functionality as a jQuery plug-in. The UI.Layout plug-in can create any UI look you want - from simple headers or sidebars, to a complex application with toolbars, menus, help-panels, status bars, sub-forms, etc.&#8221;</p>
<p>What i really like about the admin generator is its&#8230; generator feature. After a couple of minutes we have all the basic actions for our models. We can also add custom actions and modify templates. The missing component for me is navigation. We can create some simple navigation between modules alone, we can also use nice Symfony plugin: sfAdminDashPlugin or jQuery plugin: layout. The picture below shows the final result of what i&#8217;m going to do in this tutorial.<br />
<a href="http://blog.adryjanek.eu/wp-content/uploads/2009/08/layout.jpg" ><img class="aligncenter size-full wp-image-51" title="layout" src="http://blog.adryjanek.eu/wp-content/uploads/2009/08/layout.jpg" alt="Symfony admin generator + jQuery Layout plugin" width="500" height="276" /></a></p>
<p><span id="more-47"></span><br />
First we need to create new project and for example new backend application. In this example we are going to use database so database configuration is necessary. For this tutorial i have chosen Propel but it doesn&#8217;t matter which ORM you are going to use - both provide admin generator feature.</p>
<pre name="code" class="php">

&lt;?php

    symfomy generate:project sfLayout
    symfomy generate:app backend
    symfomy configure:database &quot;mysql:host=localhost;dbname=sf_layout&quot; user pass

?&gt;
</pre>
<p>I will also install and configure sfGuardPlugin (<a href="http://www.symfony-project.org/plugins/sfGuardPlugin" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');" target="_blank"> sfGuard plugin installation and configuration </a>) for some custom data:</p>
<pre name="code" class="php">

    symfony plugin:install sfGuardPlugin
</pre>
<p>I don&#8217;t want to create any other model class for such simple tutorial - You can do it for practice.</p>
<p>After that we need to download <a title="jQuery Core" href="http://jqueryui.com/download" onclick="javascript:pageTracker._trackPageview('/outbound/article/jqueryui.com');" target="_self">latest jQuery Core </a>and <a title="jQuery layout plugin" href="http://layout.jquery-dev.net/downloads.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/layout.jquery-dev.net');">jQuery layout plugin</a> version and put it in web/js/jQuery directory. We can add those scripts through view.yml file in config dir of backend appliaction. My view.yml</p>
<pre name="code" class="xml">

default:
  stylesheets:    [admin.css, jQuery/smoothness/jquery-ui-1.7.1.custom.css]

  javascripts:    [jQuery/jquery-1.3.2.min.js, jQuery/jquery-ui-1.7.1.custom.min.js, jQuery/jquery.layout.min.js]

  has_layout:     on
  layout:         layout
</pre>
<p>After that all we have to do is to setup the layout. Layout plugin configuration depends on modules you want to use for you backend appliaction. In my example i have added page module to show you how usefull accordion navigation could be. My layout.php file looks:</p>
<pre name="code" class="php">

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;?php include_http_metas() ?&gt;
    &lt;?php include_metas() ?&gt;
    &lt;?php include_title() ?&gt;
    &lt;?php include_javascripts() ?&gt;
    &lt;?php include_stylesheets()	?&gt;

    &lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot; /&gt;

    &lt;?php javascript_tag(); ?&gt;

	var outerLayout; // init global vars

	$(document).ready( function() {

		// PAGE LAYOUT
		outerLayout = $(&#039;body&#039;).layout({
			applyDefaultStyles:	true
			// AUTO-RESIZE Accordion widget when west pane resizes
		,	west__onresize:		function () { $(&quot;#accordion&quot;).accordion(&quot;resize&quot;); }
		,	west__size:			280
		,	east__size:			340
		});

		// ACCORDION - inside the West pane
		var accor = $(&quot;#accordion&quot;).accordion({
			fillSpace: true,
			header: &quot;h3&quot;,
			animated: &#039;bounceslide&#039;,
			active: false,
			navigation: true
		});

		&lt;?php switch($this-&gt;getModuleName()):

			case &#039;sfGuardUser&#039;: ?&gt;
			&lt;?php case &#039;sfGuardPermission&#039;: ?&gt;

			 	$(&quot;#accordion&quot;).accordion( &#039;activate&#039; , 0 );

				&lt;?php break; ?&gt;

	 		&lt;?php case &#039;page&#039;: ?&gt;

	 			$(&quot;#accordion&quot;).accordion( &#039;activate&#039; , 1 );

	 			&lt;?php break; ?&gt;	 		

		&lt;?php endswitch; ?&gt;
	});

	&lt;?php end_javascript_tag(); ?&gt;

  &lt;/head&gt;
  &lt;body&gt;

    &lt;div class=&quot;ui-layout-west&quot;&gt;
		&lt;div id=&quot;accordion&quot; class=&quot;basic&quot;&gt;

			&lt;h3&gt;&lt;a href=&quot;#&quot;&gt;Users&lt;/a&gt;&lt;/h3&gt;
			&lt;div&gt;
				&lt;p&gt; Manage users, groups and permissions. &lt;/p&gt;
				&lt;ul&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Users list&#039;, &#039;sfGuardUser/index&#039;) ?&gt; &lt;/li&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Add user&#039;, &#039;sfGuardUser/new&#039;) ?&gt; &lt;/li&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Groups list&#039;, &#039;sfGuardGroup/index&#039;) ?&gt; &lt;/li&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Permissions list&#039;, &#039;sfGuardPermission/index&#039;) ?&gt; &lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;

			&lt;h3&gt;&lt;a href=&quot;#&quot;&gt;Static pages&lt;/a&gt;&lt;/h3&gt;
			&lt;div&gt;
				&lt;p&gt; Manage static page content.  &lt;/p&gt;
				&lt;ul&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Pages list&#039;, &#039;page/index&#039;) ?&gt; &lt;/li&gt;
					&lt;li&gt; &lt;?php echo link_to(&#039;Add page&#039;, &#039;page/new&#039;) ?&gt; &lt;/li&gt;
				&lt;/ul&gt;
			&lt;/div&gt;

		&lt;/div&gt;
	&lt;/div&gt;

	&lt;div class=&quot;ui-layout-center&quot;&gt;

		&lt;?php echo $sf_content ?&gt;
	&lt;/div&gt;

	&lt;div class=&quot;ui-layout-north&quot;&gt;

		&lt;div class=&quot;left&quot;&gt;
			Back to &lt;strong&gt;&lt;a href=#&quot; &gt; website &lt;/a&gt;&lt;/strong&gt;
		&lt;/div&gt;

		&lt;div class=&quot;right&quot;&gt;
			Logged in as: &lt;strong&gt; &lt;?php echo $sf_user-&gt;getGuardUser()-&gt;getUsername() ?&gt; &lt;/strong&gt;
			&lt;?php echo link_to(&#039;Sign out&#039;, &#039;sfGuardAuth/signout&#039;) ?&gt;
		&lt;/div&gt;
	&lt;/div&gt;

	&lt;div class=&quot;ui-layout-south&quot;&gt;
		&lt;div class=&quot;left&quot;&gt;
			Footer
		&lt;/div&gt;

	&lt;/div&gt;

  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>I think that there is some better way to set the active tab in navigation but this one is also working well. For advance use we can also modify admin generator layout structure and put for example list filters in east panel so it could be toggleable as any other panel.</p>
<p>Nice to see your comments, enjoy.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/nsXrNWEXdII" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/08/03/symfony-12-admin-generator-jquery-layout-plugin/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/08/03/symfony-12-admin-generator-jquery-layout-plugin/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.2 - using sfForm with jquery validation plugin - part 2</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/gm151vwk7ts/</link>
		<comments>http://blog.adryjanek.eu/2009/06/15/symfony-12-using-sfform-with-jquery-validation-plugin-part-2/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 17:20:46 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[Ogólne]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[sfForm]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=41</guid>
		<description><![CDATA[New jQuery 1.3 and its user interface have a lot of great features. But if we want to use our jQuery validation plugin with 1.3 version we need to upgrade plugin version to 1.5.1 (or higher), which is still compatible with 1.2.6. New Validate Plugin version (1.5.2) came up with some nice features like integration [...]]]></description>
			<content:encoded><![CDATA[<p>New jQuery 1.3 and its user interface have a lot of great features. But if we want to use our jQuery validation plugin with 1.3 version we need to upgrade plugin version to 1.5.1 (or higher), which is still compatible with 1.2.6. New Validate Plugin version (1.5.2) came up with some nice features like integration with UI Tabs. The following example shows a real implementation of user profile form divided in three sections.<br />
<span id="more-41"></span><br />
In my example i will use sfGuardPlugin + one table for user profile. </p>
<p>First, we need to generate new project, new application and setup database configuration:</p>
<pre name="code" class="php">

&lt;?php

    symfomy generate:project sfTest
    symfomy generate:app frontend
    symfomy configure:database &quot;mysql:host=localhost;dbname=sf_test&quot; user pass

?&gt;
</pre>
<p>Next step is to install sfGuardPlugin:</p>
<pre name="code" class="php">

    symfony plugin:install sfGuardPlugin
</pre>
<p>and enable it according to its <a href="http://www.symfony-project.org/plugins/sfGuardPlugin" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.symfony-project.org');" target="_blank" >documentation</a>.</p>
<p>Now we can put profile table structure into schema.yml file:</p>
<pre name="code" class="xml">

propel:
  sf_guard_profile:
    id: ~
    user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true, onDelete: cascade }
    email: { type: varchar(128), index:unique, required: true }
    name: { type: varchar(128), required: true }
    surname: { type: varchar(128), required: true }
    education: longvarchar
    company: varchar(128)
    position: varchar(128)
    phone_number: { type: varchar(30), required: true }
    fax: varchar(25)
    comunicator: varchar(30)
    country: { type: varchar(128), required: true }
    city: { type: varchar(128), required: true }
    province: { type: varchar(128), required: true }
    address: { type: varchar(255), required: true }
    zipcode: varchar(15)
</pre>
<p>Remember to set profile configuration into app.yml:</p>
<pre name="code" class="xml">

all:
  sf_guard_plugin:
    profile_class: SfGuardProfile
    profile_field_name: user_id
</pre>
<p>Then: </p>
<pre name="code" class="xml">

    symfony propel:build-all
</pre>
<p>and create module for our example:</p>
<pre name="code" class="xml">

    symfony generate:module frontend user
</pre>
<p>Now we need to download all neccessary JavaScript files:</p>
<ul>
<li>jquery-1.3.2.js</li>
<li>jquery-ui-1.7.1.js</li>
<li>jquery.validate-1.5.2.js</li>
</ul>
<p>As i did in the previous <a href="http://blog.adryjanek.eu/2009/01/15/symfony-12-using-sfform-with-jquery-validate-plugin/"  target="_blank" >post </a>, after downloading new jquery validation plugin we need to make some changes in jquery.validation.js file, so it could work properly with Symfony sfForm (conversion form &#8220;name&#8221; to &#8220;id&#8221;). You can find corrected file <a target="_blank" href='http://blog.adryjanek.eu/wp-content/uploads/2009/06/jquery.validate.js'> here</a>.</p>
<p>We can put our bussiness logic to executeProfile action into actions.class.php but earlier we have to create our ProfileForm.class.php - we can put that file into global lib/form/ directory or lib/form of current module.<br />
<strong>ProfileForm.class.php:</strong></p>
<pre name="code" class="php">

&lt;?php

class ProfileForm extends sfGuardUserAdminForm {

  public function configure() {

  	parent::configure();

	$this-&gt;unsetAllExcept(array(
		&#039;username&#039;,
		&#039;email&#039;,
		&#039;name&#039;,
		&#039;surname&#039;,
		&#039;education&#039;,
		&#039;company&#039;,
		&#039;position&#039;,
		&#039;phone_number&#039;,
		&#039;phone_number_2&#039;,
		&#039;fax&#039;,
		&#039;communicator&#039;,
		&#039;country&#039;,
		&#039;city&#039;,
		&#039;province&#039;,
		&#039;zipcode&#039;,
		&#039;address&#039;,
		&#039;address_2&#039;
	));
	 # Edit default validators schema

	$this-&gt;validatorSchema[&#039;email&#039;] = new sfValidatorEmail();

    $this-&gt;widgetSchema-&gt;setNameFormat(&#039;profile[%s]&#039;);
  }

	protected function doSave($con = null){

	    if (is_null($con)) {

	      $con = $this-&gt;getConnection();
	    }

	    $this-&gt;updateObject();

	    $this-&gt;object-&gt;save($con);
	}
}
?&gt;
</pre>
<p>The unsetAllExcept method was presented in this <a href="http://blog.adryjanek.eu/2009/05/14/symfony-12-sfform-unsetallexcept-better-way/"  target="_blank" >post</a>.</p>
<p><strong>actions.class.php:</strong></p>
<pre name="code" class="php">

&lt;?php 

class userActions extends sfActions {

  public function executeIndex(sfWebRequest $request) {

  	$this-&gt;forward(&#039;user&#039;, &#039;profile&#039;);
  }

  public function executeProfile($request) {

  	$user = $this-&gt;getUser()-&gt;getGuardUser();

  	$this-&gt;form = new ProfileForm($user);

  	if ($request-&gt;isMethod(&#039;post&#039;) &amp;&amp; $request-&gt;hasParameter(&#039;profile&#039;)) {

  		$this-&gt;form-&gt;bind($request-&gt;getParameter(&#039;profile&#039;));

  		if ($this-&gt;form-&gt;isValid()) {

  			$this-&gt;form-&gt;save();

  			$this-&gt;getUser()-&gt;setFlash(&#039;msg&#039;, &#039;Your profile has been successfully updated&#039;);
  		} else {

  			$this-&gt;getUser()-&gt;setFlash(&#039;msg&#039;, &#039;Sorry, there are some errors listed below. &#039;);
  		}
  	}
  }
}

?&gt;
</pre>
<p>Nothing special so far, but now we need to take care of our view file.<br />
In profile template we have to split form into for example three sections: identity, experience and location. Then we can add jquery tabs and validation:</p>
<p><strong> profileSuccess.php:</strong></p>
<pre name="code" class="php">

	&lt;h1&gt; Update user profile&lt;/h1&gt;

	&lt;?php if ($sf_user-&gt;hasFlash(&#039;msg&#039;)): ?&gt;

	  &lt;div class=&quot;message&quot;&gt;&lt;?php echo $sf_user-&gt;getFlash(&#039;msg&#039;) ?&gt;&lt;/div&gt;

	&lt;?php endif; ?&gt;

	&lt;form action=&quot;&lt;?php echo url_for(&#039;user/profile&#039;) ?&gt;&quot; id=&quot;profileForm&quot; method=&quot;post&quot; &gt;

	&lt;div id=&quot;tabs&quot;&gt;

	    &lt;ul&gt;
	        &lt;li&gt;&lt;a href=&quot;#identity&quot;&gt;&lt;span&gt;Identity data&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	        &lt;li&gt;&lt;a href=&quot;#experience&quot;&gt;&lt;span&gt;Experience/Job information&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	        &lt;li&gt;&lt;a href=&quot;#location&quot;&gt;&lt;span&gt;Location&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	    &lt;/ul&gt;

	    &lt;div id=&quot;identity&quot;&gt;

			&lt;table&gt;

				&lt;?php echo $form[&#039;username&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;email&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;name&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;surname&#039;]-&gt;renderRow() ?&gt;

			&lt;/table&gt;
		&lt;/div&gt;

		&lt;div id=&quot;experience&quot;&gt;

			&lt;table&gt;

				&lt;?php echo $form[&#039;education&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;company&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;position&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;phone_number&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;fax&#039;]-&gt;renderRow() ?&gt;

			&lt;/table&gt;

		&lt;/div&gt;

		&lt;div id=&quot;location&quot;&gt;

			&lt;table&gt;

				&lt;?php echo $form[&#039;country&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;province&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;city&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;address&#039;]-&gt;renderRow() ?&gt;
				&lt;?php echo $form[&#039;zipcode&#039;]-&gt;renderRow() ?&gt;
			&lt;/table&gt;
		&lt;/div&gt;

	&lt;/div&gt;

		&lt;input type=&quot;submit&quot; value=&quot;Update profile&quot; /&gt;

	&lt;/form&gt; 

	&lt;?php javascript_tag(); ?&gt;

		$(document).ready(function(){

    		var tabs = $(&quot;#tabs&quot;).tabs();

			var validator = $(&quot;#profileForm&quot;).validate({
				rules: {
					profile_username: &quot;required&quot;,
					profile_email: {
						required: true,
						email: true
					},
					profile_name: &quot;required&quot;,
					profile_surname: &quot;required&quot;,
					profile_phone_number: {
						required: true,
						number: true
					},
					profile_country: &quot;required&quot;,
					profile_province: &quot;required&quot;,
					profile_city: &quot;required&quot;,
					profile_address: &quot;required&quot;
				},
				errorPlacement: function(label, element) {

						label.insertAfter(element);
				}

			});

			validator.focusInvalid = function() {
				if( this.settings.focusInvalid ) {
					try {
						var focused = $(this.findLastActive() || this.errorList.length &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; this.errorList[0].element || []).filter(&quot;:hidden&quot;);

						tabs.tabs(&quot;select&quot;, tabs.find(&quot;&gt;div&quot;).index(focused.parents(&#039;div:first&#039;)));
						focused.focus();

					} catch(e) {
						// ignore IE throwing errors when focusing hidden elements
					}
				}
			};

		});

	&lt;?php end_javascript_tag(); ?&gt;
</pre>
<p>Putting it together with server side validation provided by Symfony forms, we have nice, simple and complex forms validation system that should look like this:<br />
<a href='http://blog.adryjanek.eu/wp-content/uploads/2009/06/form1.jpg'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/06/form1.jpg" alt="" title="form1" width="500" height="174" class="aligncenter size-full wp-image-45" /></a></p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2009/06/form2.jpg'><img src="http://blog.adryjanek.eu/wp-content/uploads/2009/06/form2.jpg" alt="" title="form2" width="500" height="279" class="aligncenter size-full wp-image-46" /></a></p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/gm151vwk7ts" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/06/15/symfony-12-using-sfform-with-jquery-validation-plugin-part-2/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/06/15/symfony-12-using-sfform-with-jquery-validation-plugin-part-2/</feedburner:origLink></item>
		<item>
		<title>Symfony 1.2 - sfForm - unsetAllExcept - better way?</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/OFupRdy-sYE/</link>
		<comments>http://blog.adryjanek.eu/2009/05/14/symfony-12-sfform-unsetallexcept-better-way/#comments</comments>
		<pubDate>Thu, 14 May 2009 17:39:31 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[propel]]></category>

		<category><![CDATA[sfForm]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=43</guid>
		<description><![CDATA[It&#8217;s kind of update of function: unsetAllExcept. Lately I had a problem with unsetting some default widgets. Using for example propel and relations m-n, auto-generated forms have widgets that cannot be unsets using the current version of function - it only unset widgets by form object fields. 
I think it could be useful: 


&#60;?php

  [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s kind of update of function: <a href="http://blog.adryjanek.eu/2008/12/12/symfony-12-sfform-yet-another-useful-function/"  target="_blank" >unsetAllExcept</a>. Lately I had a problem with unsetting some default widgets. Using for example propel and relations m-n, auto-generated forms have widgets that cannot be unsets using the current version of function - it only unset widgets by form object fields. </p>
<p>I think it could be useful: </p>
<pre name="code" class="php">

&lt;?php

  /**
   *  unset all fields except given parameters
   *
   * @param array $fields Array of fields
   */
  public function unsetAllExcept($fields = array())
  {
  	$tmp = array_keys($this-&gt;widgetSchema-&gt;getFields());

  	foreach(array_diff($tmp, $fields) as $value){

  		unset($this[$value]);
  	}
  }

?&gt;
</pre>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/OFupRdy-sYE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2009/05/14/symfony-12-sfform-unsetallexcept-better-way/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2009/05/14/symfony-12-sfform-unsetallexcept-better-way/</feedburner:origLink></item>
	</channel>
</rss>
