<?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>Tue, 08 Jun 2010 13:13:31 +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 - how to set up default database encoding?</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/31uISCGuLIA/</link>
		<comments>http://blog.adryjanek.eu/2010/06/08/symfony-how-to-set-up-default-database-encoding/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 13:13:31 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<category><![CDATA[Doctrine]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=74</guid>
		<description><![CDATA[Maybe it&#8217;s nothing special and difficult but i remember the day (some time go)  when i had a problem with setting up default database encoding in my application. I recently received some questions about it so i decided to post this here and help some of you.

My solutions (maybe there is some better way to [...]]]></description>
			<content:encoded><![CDATA[<p>Maybe it&#8217;s nothing special and difficult but i remember the day (some time go)  when i had a problem with setting up default database encoding in my application. I recently received some questions about it so i decided to post this here and help some of you.</p>
<p><span id="more-74"></span></p>
<p>My solutions (maybe there is some better way to do this):</p>
<pre name="code" class="xml">

all:
  doctrine:
    class: sfDoctrineDatabase   # or sfPropelDatabase
    param:
      dsn:      mysql:host=host_name;dbname=database_name
      username: default_user
      password: pass
      encoding: utf8
      attributes: { default_table_collate: utf8_unicode_ci, default_table_charset: utf8 }
</pre>
<p>And that&#8217;s really all.</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/31uISCGuLIA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2010/06/08/symfony-how-to-set-up-default-database-encoding/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2010/06/08/symfony-how-to-set-up-default-database-encoding/</feedburner:origLink></item>
		<item>
		<title>Advanced data filtering with Symfony 1.4 and ExtJS 3.2 [english]</title>
		<link>http://feedproxy.google.com/~r/ProgramistaPhp/~3/PNSg1IrrDzk/</link>
		<comments>http://blog.adryjanek.eu/2010/06/03/advanced-data-filtering-with-symfony-14-and-extjs-32-english/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 15:26:33 +0000</pubDate>
		<dc:creator>Kamil Adryjanek</dc:creator>
		
		<category><![CDATA[Ext JS]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Symfony]]></category>

		<category><![CDATA[Doctrine]]></category>

		<category><![CDATA[extjs]]></category>

		<category><![CDATA[grid]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.adryjanek.eu/?p=63</guid>
		<description><![CDATA[After a couple of weeks I finally found some time to write about Symfony and ExtJS. This time i want to show how to put together to work Symfony 1.4, ExtJS 3.2 and Grid Filter Plugin - for me it&#8217;s the one of most powerfull filtering solutions i have ever seen.
Since my last entry about [...]]]></description>
			<content:encoded><![CDATA[<p>After a couple of weeks I finally found some time to write about Symfony and ExtJS. This time i want to show how to put together to work Symfony 1.4, ExtJS 3.2 and Grid Filter Plugin - for me it&#8217;s the one of most powerfull filtering solutions i have ever seen.<br />
Since my last entry about displaying data in ExtJS Grid Panel i have updated Ext library to 3.2 version - they have added some nice features (more information you can find in <a href="http://www.extjs.com/products/js/CHANGES_ext-3.1.0.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.extjs.com');">changelog 3.1</a> and <a href="http://www.extjs.com/products/js/CHANGES_ext-3.2.0.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.extjs.com');">changelog 3.2</a>) and changed some ExtJs components (more details you will find later).</p>
<p><span id="more-63"></span></p>
<p><strong>Configuration and project setup</strong></p>
<p>Information about how to setup new Symfony project and configure it to work well with ExtJS - you can find in this <a href="http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english" >entry</a> - i&#8217;m not gonna repeat all steps again. Notice that you should download latest ExtJS version: 3.2 and set up view.yml file to attach neccessary files. You should also load sample data - we need it for our example.</p>
<p>After setting up the environment we can start coding. </p>
<p><div class="note"><div class="dropshadow"><div class="notehelp">In this example i will use a little bit diffrent type of configuration of ExtJS components - this is because next time i would like to show how to add funcionality of creating and updating new records. </div></div></div></p>
<p><strong>ExtJS components</strong></p>
<p>This time i&#8217;m going to put all JavaScript code in separate files - it is really good practice for building bigger ExtJS applications than in this example. First i will create grid.js file and put there grid component class and other configuration - i will create my own custom component class: App.country.Grid which inherits from Ext.grid.GridPanel - it&#8217;s not really needed now but it will save us time next time. Commnets should help you understand the concept:</p>
<pre name="code" class="javascript">

// Typical data Store automatically configured with a Ext.data.JsonReader.
var store = new Ext.data.JsonStore({
	// store configs
	url: &#039;default/list&#039;,  // url for retreiving data
    autoLoad: true,
    // reader configs
    totalProperty: &#039;total&#039;,
    successProperty: &#039;success&#039;,  // response status name
    idProperty: &#039;id&#039;,
    root: &#039;data&#039;,
    fields: [&#039;id&#039;, &#039;name&#039;, &#039;description&#039;, &#039;population&#039;, &#039;created_at&#039;]
});

// Columns configuration
var columns =  [
    {header: &quot;ID&quot;, width: 50, fixed: true, sortable: true, dataIndex: &#039;id&#039;},
    {header: &quot;Country&quot;, width: 50, sortable: true, dataIndex: &#039;name&#039; },
    {header: &quot;Description&quot;, width: 100, sortable: true, dataIndex: &#039;description&#039; },
    {header: &quot;Population&quot;, width: 50, sortable: true, dataIndex: &#039;population&#039; },
    {header: &quot;Created at&quot;, width: 150, fixed:true, sortable: true, dataIndex: &#039;created_at&#039; }
];

Ext.ns(&#039;App&#039;, &#039;App.country&#039;);
// my custom grid component
App.country.Grid = Ext.extend(Ext.grid.GridPanel, {

    initComponent : function() {

        // typical viewConfig
        this.viewConfig = {
            forceFit: true,
            emptyText: &#039;No data found.&#039;
        };

        App.country.Grid.superclass.initComponent.call(this);
    }
});
</pre>
<p>I think this code do not need additional explanations.</p>
<p>Next step is to create main app.js file - place where i&#8217;m going to put my components logic (components initialization)  - nothing special so far - simple retrieving data and displaying it in grid. In this example i will place grid into simple window component - for better usability- it&#8217;s another good example of using ExtJS components. Code responsible for that:</p>
<pre name="code" class="javascript">

// when document is ready
Ext.onReady(function() {

	Ext.QuickTips.init();

	// create my custom grid component
    var grid = new App.country.Grid({

        store: store,  // data store for grid
        columns : columns,  //columns configuration
        plugins: [filters],  // additional plugin - Grid Filter Plugin
        bbar: new Ext.PagingToolbar({  //bottom bar configuration
    		pageSize: 15,   // records per page
    		store: store,
    		displayInfo: true
    	})
    });

    // simple window for grid
    var win = new Ext.Window({
        title: &#039;Advanced data filtering with Grid Filter Plugin&#039;,
        height: 410,
        width: 800,
        layout: &#039;fit&#039;,
        items: grid  // just one item
    });

    win.show();  // display window with grid

});
</pre>
<p><strong>On the server side</strong></p>
<p>There is one more thing to get it to work - we need PHP code on the server side. We can use code from the latest <a href="http://blog.adryjanek.eu/2009/12/13/symfony-14-and-extjs-displaying-data-in-gridpanel-english" >entry </a>or use the following:</p>
<pre name="code" class="php">

  public function executeList(sfWebRequest $request) {

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

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

	 # conditions for sorting
	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-&gt;setQuery($query);
	$pager-&gt;setPage($page);
	$pager-&gt;init();

	$result = array();

	 # format 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;success&#039;	=&gt; true,
		&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
		&#039;data&#039;		=&gt; $result
	)));
  }
</pre>
<p>Calling default action of our application we should achieved the following:</p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2010/06/ext1.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2010/06/ext1.png" alt="" title="Simple window with grid" width="500" height="245" class="aligncenter size-full wp-image-72" /></a></p>
<p><strong>Grid Filter plugin</strong></p>
<p>Next step is to apply Grid Filter plugin to our example.</p>
<p><div class="note"><div class="dropshadow"><div class="notetip">Since ExtJS 3.1 Grid filter plugin has been included in ExtJS package, so it&#8217;s not necessary to download any additional code.</div></div></div></p>
<p>I just only copied Filter plugin folder from Ext/examples/ux to Ext/ux for better code organisation. To add all neccessary JS and CSS files we need to edit view.yml file - final version should looks similar to this:</p>
<pre name="code" class="xml">

  stylesheets:
    - ../js/ext-3.2.0/resources/css/ext-all.css
    - ../js/ext-3.2.0/ux/gridfilters/css/GridFilters.css
    - ../js/ext-3.2.0/ux/gridfilters/css/RangeMenu.css

  javascripts:
    - ext-3.2.0/adapter/ext/ext-base-debug.js
    - ext-3.2.0/ext-all-debug.js
    - ext-3.2.0/ux/gridfilters/menu/RangeMenu.js
    - ext-3.2.0/ux/gridfilters/menu/ListMenu.js
    - ext-3.2.0/ux/gridfilters/GridFilters.js
    - ext-3.2.0/ux/gridfilters/filter/Filter.js
    - ext-3.2.0/ux/gridfilters/filter/StringFilter.js
    - ext-3.2.0/ux/gridfilters/filter/DateFilter.js
    - ext-3.2.0/ux/gridfilters/filter/ListFilter.js
    - ext-3.2.0/ux/gridfilters/filter/NumericFilter.js
    - ext-3.2.0/ux/gridfilters/filter/BooleanFilter.js
    - grid.js
    - app.js
</pre>
<p>Now we can configure filter component:</p>
<pre name="code" class="javascript">

var filters = new Ext.ux.grid.GridFilters({
    local: false,   // enable remote filtering
    filters: [{
        type: &#039;numeric&#039;,  // filter type
        dataIndex: &#039;id&#039;    // column name
    }, {
        type: &#039;string&#039;,
        dataIndex: &#039;name&#039;
    }, {
        type: &#039;string&#039;,
        dataIndex: &#039;description&#039;
    }, {
    	type: &#039;numeric&#039;,
        dataIndex: &#039;population&#039;
    }, {
        type: &#039;date&#039;,
        dataIndex: &#039;created_at&#039;
    }]
}); 
</pre>
<p>And enable it in grid:</p>
<pre name="code" class="javascript">

    var grid = new App.country.Grid({

        store: store,  // data store for grid
        columns : columns,  //columns configuration
        plugins: [filters],  // additional plugin - Grid Filter Plugin
        bbar: new Ext.PagingToolbar({  //bottom bar configuration
    		pageSize: 15,   // records per page
    		store: store,
    		displayInfo: true
    	})
    });
</pre>
<p>So filter component could work properly we need to write additional PHP code responsible for filtering data. Using symfony and Doctrine Query Language it is really easy. The fallowing code of action.class.php presents complete code:</p>
<pre name="code" class="php">

  public function executeList(sfWebRequest $request) {

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

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

	 # conditions for sorting
	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));
	}

	 # code resposible for filtering data
	foreach($request-&gt;getParameter(&#039;filter&#039;) as $filter) {

		 # comparison condition
		if (isset($filter[&#039;data&#039;][&#039;comparison&#039;])) {

			switch($filter[&#039;data&#039;][&#039;comparison&#039;]) {

				case &#039;eq&#039;:

					$comparison = &#039;=&#039;;
					break;

				case &#039;lt&#039;:

					$comparison = &#039;&lt;&#039;;
					break;

				case &#039;gt&#039;:

					$comparison = &#039;&gt;&#039;;
					break;
			}
		}

		 # switch 5 filter types
		switch($filter[&#039;data&#039;][&#039;type&#039;]) {

			case &#039;boolean&#039;:

				$query-&gt;addWhere(sprintf(&#039;c.%s = ?&#039;, $filter[&#039;field&#039;]), $filter[&#039;data&#039;][&#039;value&#039;]);

				break;

			case &#039;string&#039;:

				$query-&gt;addWhere(sprintf(&#039;c.%s LIKE ?&#039;, $filter[&#039;field&#039;]), &#039;%&#039;.$filter[&#039;data&#039;][&#039;value&#039;].&#039;%&#039;);

				break;

			case &#039;numeric&#039;:

				$query-&gt;addWhere(sprintf(&#039;c.%s %s ?&#039;, $filter[&#039;field&#039;], $comparison), $filter[&#039;data&#039;][&#039;value&#039;]);

				break;

			case &#039;list&#039;:

				$query-&gt;whereIn(sprintf(&#039;c.%s&#039;, $filter[&#039;field&#039;]), explode(&#039;,&#039;, $filter[&#039;data&#039;][&#039;value&#039;])); 

				break;

			case &#039;date&#039;:

				$query-&gt;addWhere(sprintf(&#039;c.%s %s ?&#039;, $filter[&#039;field&#039;], $comparison), date(&#039;Y-m-d&#039;, strtotime($filter[&#039;data&#039;][&#039;value&#039;])));

				break;

			default:

				break;
		}
	}

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

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

	$result = array();

	 # format 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;success&#039;	=&gt; true,
		&#039;total&#039;		=&gt; $pager-&gt;getNbResults(),
		&#039;data&#039;		=&gt; $result
	)));
  }

}
</pre>
<p>Thats all. As a result we should get: </p>
<p><a href='http://blog.adryjanek.eu/wp-content/uploads/2010/06/ext2.png'><img src="http://blog.adryjanek.eu/wp-content/uploads/2010/06/ext2.png" alt="" title="Sample Grid with Filter plugin" width="500" height="246" class="aligncenter size-full wp-image-73" /></a></p>
<p>Enyoj!</p>
<img src="http://feeds.feedburner.com/~r/ProgramistaPhp/~4/PNSg1IrrDzk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.adryjanek.eu/2010/06/03/advanced-data-filtering-with-symfony-14-and-extjs-32-english/feed/</wfw:commentRss>
		<feedburner:origLink>http://blog.adryjanek.eu/2010/06/03/advanced-data-filtering-with-symfony-14-and-extjs-32-english/</feedburner:origLink></item>
		<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[sfForm]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[Tutorial]]></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[extjs]]></category>

		<category><![CDATA[i18n]]></category>

		<category><![CDATA[Tutorial]]></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[extjs]]></category>

		<category><![CDATA[grid]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[Tutorial]]></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[extjs]]></category>

		<category><![CDATA[symfony]]></category>

		<category><![CDATA[Tutorial]]></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[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>
	</channel>
</rss>
