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

<channel>
	<title>PHPBlog.it &#187; shiny</title>
	<atom:link href="http://phpblog.it/tag/shiny/feed/" rel="self" type="application/rss+xml" />
	<link>http://phpblog.it</link>
	<description>Solo un altro blog targato WordPress</description>
	<lastBuildDate>Mon, 30 Jan 2012 10:36:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>symfony 1.1: finalmente la documentazione</title>
		<link>http://phpblog.it/2008/06/20/symfony-11-finalmente-la-documentazione/</link>
		<comments>http://phpblog.it/2008/06/20/symfony-11-finalmente-la-documentazione/#comments</comments>
		<pubDate>Fri, 20 Jun 2008 05:00:26 +0000</pubDate>
		<dc:creator>Davide Borsatto</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[shiny]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://phpblog.it/2008/06/20/symfony-11-finalmente-la-documentazione/</guid>
		<description><![CDATA[Mentre sono costretto momentaneamente ad utilizzare Opera durante l&#8217;atteso aggiornamento a Firefox 3, scopro che finalmente comincia ad esserci della documentazione decente sulla maggiore novità della più recente incarnazione di symfony: il Form Framework. Finora su form c&#8217;era qualcosa qua e la, ma niente di concreto. Ora è iniziata con quattro capitoli la pubblicazione dello [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://172.18.0.13/wordpress/wp-content/uploads/2008/06/symfony.jpg" alt="Symfony" />Mentre sono costretto momentaneamente ad utilizzare Opera durante l&#8217;atteso aggiornamento a Firefox 3, <a href="http://phpblog.it/2008/06/19/symfony-forms-in-action-libro-online/" title="documentazione symfony">scopro</a> che finalmente comincia ad esserci della <a href="http://www.symfony-project.org/blog/2008/06/18/the-symfony-forms-in-action-book-is-online" title="symfony Form Framework">documentazione decente</a> sulla maggiore novità della più recente incarnazione di symfony: il <strong>Form Framework</strong>.</p>
<p><span id="more-149"></span> Finora su form c&#8217;era qualcosa qua e la, ma niente di concreto. Ora è iniziata con quattro capitoli la pubblicazione dello pseudo libro &#8220;<em>the symfony Forms in Action</em>&#8220;. Grande notizia! Utilizzando questa documentazione, più prendendo spunto da uno <a href="http://www.symfony-project.org/snippets/snippet/305">snippet</a> all&#8217;interno della documentazione, ho creato un completo form di login per il mio forum con symfony.</p>
<p>Il form si poggia su tre file, all&#8217;interno della directory <em>lib/</em>: <strong>lib/myLoginValidator.class.php</strong>, <strong>lib/sfWidgetFormSchemaFormatterDiv</strong> e <strong>lib/form/LoginForm.class.php</strong>. Vediamoli:</p>
<p><strong>LoginForm.class.php</strong></p>
<p>[source:php]<br />
&lt;?php</p>
<p>/**<br />
* Login form.<br />
*<br />
* @package    form<br />
* @subpackage login<br />
* @version    SVN: $Id: sfPropelFormTemplate.php 6174 2007-11-27 06:22:40Z fabien $<br />
*/<br />
class LoginForm extends sfForm<br />
{</p>
<p>private function initValidators()<br />
{<br />
$this-&gt;usernameValidator = new sfValidatorAnd<br />
(<br />
array<br />
(<br />
new sfValidatorString<br />
(<br />
array<br />
(<br />
&#8216;min_length&#8217; =&gt; 4,<br />
&#8216;max_length&#8217; =&gt; 50<br />
),<br />
array<br />
(<br />
&#8216;min_length&#8217; =&gt; &#8216;The username should be al least three characters long&#8217;,<br />
&#8216;max_length&#8217; =&gt; &#8216;The username should be be fifty characters long al most&#8217;<br />
)<br />
),</p>
<p>new sfValidatorCallback<br />
(<br />
array<br />
(<br />
&#8216;callback&#8217; =&gt; array<br />
(<br />
&#8216;myLoginValidator&#8217;, &#8216;execute&#8217;<br />
),<br />
&#8216;arguments&#8217; =&gt; array<br />
(<br />
)<br />
),<br />
array<br />
(<br />
&#8216;invalid&#8217; =&gt; &#8216;This username/password combination is unknown&#8217;<br />
)<br />
)<br />
),</p>
<p>array<br />
(<br />
&#8216;required&#8217; =&gt; true<br />
),</p>
<p>array<br />
(<br />
&#8216;required&#8217; =&gt; &#8216;The username is mandatory&#8217;<br />
)<br />
);</p>
<p>$this-&gt;passwordValidator = new sfValidatorString<br />
(<br />
array<br />
(<br />
&#8216;required&#8217; =&gt; true<br />
),<br />
array<br />
(<br />
&#8216;required&#8217; =&gt; &#8216;The password is mandatory&#8217;<br />
)<br />
);</p>
<p>$this-&gt;referrerValidator = new sfValidatorString<br />
(<br />
array<br />
(<br />
&#8216;required&#8217; =&gt; false<br />
)<br />
);</p>
<p>}</p>
<p>private function initWidgets()<br />
{</p>
<p>$this-&gt;usernameWidget = new sfWidgetFormInput<br />
(<br />
array(),<br />
array<br />
(<br />
&#8216;id&#8217; =&gt; &#8216;username&#8217;,<br />
&#8216;size&#8217; =&gt; 25<br />
)<br />
);</p>
<p>$this-&gt;passwordWidget = new sfWidgetFormInputPassword<br />
(<br />
array(),<br />
array<br />
(<br />
&#8216;id&#8217; =&gt; &#8216;password&#8217;,<br />
&#8216;size&#8217; =&gt; 25<br />
)<br />
);</p>
<p>$this-&gt;referrerWidget = new sfWidgetFormInputHidden<br />
(<br />
array(),<br />
array<br />
(<br />
&#8216;id&#8217; =&gt; &#8216;referrer&#8217;<br />
)<br />
);</p>
<p>}</p>
<p>public function configure()<br />
{<br />
$this-&gt;initValidators();<br />
$this-&gt;initWidgets();</p>
<p>$this-&gt;setValidators<br />
(<br />
array<br />
(<br />
&#8216;username&#8217; =&gt; $this-&gt;usernameValidator,<br />
&#8216;password&#8217; =&gt; $this-&gt;passwordValidator,<br />
&#8216;referrer&#8217; =&gt; $this-&gt;referrerValidator<br />
)<br />
);</p>
<p>$this-&gt;setWidgets<br />
(<br />
array<br />
(<br />
&#8216;username&#8217; =&gt; $this-&gt;usernameWidget,<br />
&#8216;password&#8217; =&gt; $this-&gt;passwordWidget,<br />
&#8216;referrer&#8217; =&gt; $this-&gt;referrerWidget<br />
)<br />
);</p>
<p>$decorator = new sfWidgetFormSchemaFormatterDiv<br />
(<br />
$this-&gt;getWidgetSchema()<br />
);</p>
<p>$this-&gt;getWidgetSchema()-&gt;addFormFormatter<br />
(<br />
&#8216;div&#8217;, $decorator<br />
);</p>
<p>$this-&gt;getWidgetSchema()-&gt;setFormFormatterName<br />
(<br />
&#8216;div&#8217;<br />
);</p>
<p>$this-&gt;getWidgetSchema()-&gt;setHelps<br />
(<br />
array<br />
(<br />
&#8216;username&#8217; =&gt; &#8216;Please enter your username&#8217;,<br />
&#8216;password&#8217; =&gt; &#8216;Please enter your password&#8217;<br />
)<br />
);<br />
}</p>
<p>}<br />
[/source]</p>
<p><strong>sfWidgetFormSchemaFormatterDiv</strong><br />
[source:php]<br />
&lt;?php</p>
<p>class sfWidgetFormSchemaFormatterDiv extends sfWidgetFormSchemaFormatter<br />
{<br />
protected<br />
$rowFormat = &#8216;%field%<br />
%error%<br />
&#8216;,<br />
$helpFormat = &#8216;&lt;span class=&#8221;help&#8221;&gt;%help%&lt;/span&gt;&#8217;,<br />
$errorRowFormat = &#8216;&lt;div&gt;%errors%&lt;/div&gt;&#8217;,<br />
$errorListFormatInARow = &#8216;%errors%&#8217;,<br />
$errorRowFormatInARow = &#8216;&lt;div class=&#8221;clearer&#8221;&gt;&lt;/div&gt;&lt;span class=&#8221;formError&#8221;&gt;%error%&lt;/span&gt;&lt;div class=&#8221;clearer&#8221;&gt;&lt;/div&gt;&#8217;,<br />
$namedErrorRowFormatInARow = &#8216;%name%: %error%&lt;br /&gt;&#8217;,<br />
$decoratorFormat = &#8216;&lt;div id=&#8221;formContainer&#8221;&gt;%content%&lt;/div&gt;&#8217;;<br />
}<br />
[/source]</p>
<p><strong>myLoginValidator</strong><br />
[source:php]<br />
&lt;?php</p>
<p>class myLoginValidator<br />
{</p>
<p>public static function execute($validator, $value, $arguments)<br />
{<br />
$username = sfContext::getInstance()-&gt;getRequest()-&gt;getParameter(&#8216;username&#8217;);<br />
$password = sfContext::getInstance()-&gt;getRequest()-&gt;getParameter(&#8216;password&#8217;);<br />
$c = new Criteria();<br />
$c-&gt;add(AuthorPeer::NAME, $username);<br />
$c-&gt;add(AuthorPeer::PASSWORD, $password);<br />
$user = AuthorPeer::doSelectOne($c);<br />
if ($user)<br />
{<br />
sfContext::getInstance()-&gt;getUser()-&gt;setData(<br />
$user-&gt;getID(),<br />
$user-&gt;getGroupID(),<br />
$user-&gt;getName()<br />
);<br />
}<br />
else<br />
{<br />
throw new sfValidatorError($validator, &#8216;invalid&#8217;, array(&#8216;value&#8217; =&gt; $value, &#8216;invalid&#8217; =&gt; $validator-&gt;getOption(&#8216;invalid&#8217;)));<br />
}<br />
}</p>
<p>}<br />
[/source]</p>
<p>L&#8217;uso è molto semplice, come vediamo ora nell&#8217;azione e nel template:<br />
<strong>apps/frontend/modules/user/actions/actions.class.php</strong><br />
[source:php]<br />
public function executeLogin($request)<br />
{<br />
$this-&gt;getUser()-&gt;clearData();<br />
$this-&gt;getUser()-&gt;setLogged(false);</p>
<p>$this-&gt;form = new LoginForm();</p>
<p>if ($request-&gt;isMethod(&#8216;post&#8217;))<br />
{<br />
$this-&gt;form-&gt;bind(<br />
array (&#8216;username&#8217; =&gt; $request-&gt;getParameter(&#8216;username&#8217;),<br />
&#8216;password&#8217; =&gt; $request-&gt;getParameter(&#8216;password&#8217;),<br />
&#8216;referrer&#8217; =&gt; $request-&gt;getParameter(&#8216;referrer&#8217;)<br />
)<br />
);</p>
<p>$this-&gt;form-&gt;setDefault(&#8216;referrer&#8217;, $request-&gt;getParameter(&#8216;referrer&#8217;));</p>
<p>if ($this-&gt;form-&gt;isValid())<br />
{<br />
$this-&gt;getUser()-&gt;setLogged(true);<br />
$this-&gt;redirect($request-&gt;getParameter(&#8216;referrer&#8217;));<br />
}<br />
else<br />
{<br />
$this-&gt;form-&gt;setDefault(&#8216;referrer&#8217;, $request-&gt;getParameter(&#8216;referrer&#8217;));<br />
}<br />
}<br />
else<br />
{<br />
$this-&gt;form-&gt;setDefault(&#8216;referrer&#8217;, $_SERVER['HTTP_REFERER']);<br />
}<br />
}<br />
[/source]<br />
<strong>apps/frontend/modules/user/templates/loginSuccess.php</strong><br />
[source:php]<br />
&lt;h1&gt;Login&lt;/h1&gt;<br />
&lt;div id=&#8221;formContainer&#8221;&gt;<br />
&lt;?php if ($form-&gt;getErrorSchema()-&gt;getErrors()): ?&gt;<br />
&lt;div id=&#8221;errors&#8221;&gt;<br />
&lt;ul&gt;<br />
&lt;?php foreach($form-&gt;getErrorSchema() as $error): ?&gt;<br />
&lt;li&gt;&lt;?php echo $error ?&gt;&lt;/li&gt;<br />
&lt;?php endforeach; ?&gt;<br />
&lt;/ul&gt;<br />
&lt;/div&gt;<br />
&lt;?php endif; ?&gt;<br />
&lt;form action=&#8221;&lt;?php echo url_for(&#8216;@user_login&#8217;) ?&gt;&#8221; method=&#8221;post&#8221;&gt;<br />
&lt;div class=&#8221;formElement&#8221;&gt;<br />
&lt;?php echo $form['username']-&gt;renderLabel($form['username']-&gt;renderLabelName()) ?&gt;</p>
<p>&lt;?php echo $form['username']-&gt;renderRow($form-&gt;getWidgetSchema()-&gt;getHelp(&#8216;username&#8217;)) ?&gt;<br />
&lt;/div&gt;<br />
&lt;div class=&#8221;clearer&#8221;&gt;&lt;/div&gt;<br />
&lt;div class=&#8221;formElement&#8221;&gt;<br />
&lt;?php echo $form['password']-&gt;renderLabel($form['password']-&gt;renderLabelName()) ?&gt;</p>
<p>&lt;?php echo $form['password']-&gt;renderRow($form-&gt;getWidgetSchema()-&gt;getHelp(&#8216;password&#8217;)) ?&gt;<br />
&lt;/div&gt;<br />
&lt;div class=&#8221;clearer&#8221;&gt;&lt;/div&gt;<br />
&lt;div class=&#8221;formElement&#8221;&gt;<br />
&lt;?php echo $form['referrer']-&gt;render(array(&#8216;value&#8217; =&gt; $form-&gt;getDefault(&#8216;referrer&#8217;))) ?&gt;<br />
&lt;/div&gt;<br />
&lt;div class=&#8221;clearer&#8221;&gt;&lt;/div&gt;<br />
&lt;div class=&#8221;formElement&#8221;&gt;<br />
&lt;button type=&#8221;submit&#8221;&gt;Login&lt;/button&gt;<br />
&lt;/div&gt;<br />
&lt;/form&gt;<br />
&lt;/div&gt;<br />
[/source]<br />
Per oggi ho intenzione di lasciarvi con questa <em>vagonata</em> di codice da studiare, ed un consiglio: date un&#8217;occhiata alla documentazione, che come sempre è per symfony di altissimo livello. Nel caso qualcosa non fosse chiaro non esitate a chiedere, nei commenti. A presto!</p>
]]></content:encoded>
			<wfw:commentRss>http://phpblog.it/2008/06/20/symfony-11-finalmente-la-documentazione/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>symfony: le viste</title>
		<link>http://phpblog.it/2008/06/11/symfony-le-viste/</link>
		<comments>http://phpblog.it/2008/06/11/symfony-le-viste/#comments</comments>
		<pubDate>Wed, 11 Jun 2008 05:00:52 +0000</pubDate>
		<dc:creator>Davide Borsatto</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[shiny]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://phpblog.it/2008/06/11/symfony-le-viste/</guid>
		<description><![CDATA[Con oggi esploreremo l&#8217;argomento viste, template e layout con symfony. Ma prima di questo, voglio solo aggiornare il codice postato l&#8217;altro giorno. La funzione findData infatti non è ottimizzata, in quanto carica tutti i record indiscriminatamente. Per questo va modificata come segue: private function findData($forumID) { $c = new Criteria(); $c-&#62;add(ForumPeer::PARENT_ID, $forumID); $this-&#62;childs = ForumPeer::doSelect($c); [...]]]></description>
			<content:encoded><![CDATA[<p>Con oggi esploreremo l&#8217;argomento viste, template e layout con symfony.</p>
<p><span id="more-140"></span>Ma prima di questo, voglio solo aggiornare il codice postato l&#8217;altro giorno. La funzione findData infatti non è ottimizzata, in quanto carica tutti i record indiscriminatamente. Per questo va modificata come segue:<br />
<code><br />
private function findData($forumID)<br />
{<br />
$c = new Criteria();<br />
$c-&gt;add(ForumPeer::PARENT_ID, $forumID);<br />
$this-&gt;childs = ForumPeer::doSelect($c);<br />
$c = new Criteria();<br />
$c-&gt;add(ThreadPeer::FORUM_ID, $forumID);<br />
$c-&gt;addDescendingOrderByColumn(ThreadPeer::UPDATED_ON);<br />
$this-&gt;limit = ($this-&gt;getRequest()-&gt;getParameter('page', 1) * 10) - 1;<br />
$this-&gt;offset = ($this-&gt;getRequest()-&gt;getParameter('page', 1) - 1) * 10;<br />
$this-&gt;page = $this-&gt;getRequest()-&gt;getParameter('page', 1);<br />
$c-&gt;setLimit($this-&gt;limit);<br />
$c-&gt;setOffset($this-&gt;offset);<br />
$this-&gt;threads = ThreadPeer::doSelect($c);<br />
}<br />
</code><br />
Con questo codice aggiungo ai criteri di selezione un ordinamento discendente sulla colonna updated_on, ed aggiungo un limite ed un offset in base al parametro get &lt;code&gt;page&lt;/code&gt;. Utilizzo la forma $this-&gt;limit e non semplicemente $limit (anche per offset e page) perché avrò bisogno di accedere ad essi nella vista..</p>
<p>..che vi presento ora (apps/frontend/modules/forum/templates/viewSuccess.php):<br />
<code><br />
&lt;?php foreach ($forum-&gt;getPath() as $path): ?&gt;<br />
&lt;?php echo link_to($path-&gt;getTitle(),'@view_forum_by_title?title='.$path-&gt;getTitle()) ?&gt; &gt;&gt;<br />
&lt;?php endforeach; ?&gt;<br />
</code><code><br />
&lt;h1&gt;&lt;?php echo $forum-&gt;getTitle() ?&gt; Forum&lt;/h1&gt;<br />
&lt;h3&gt;&lt;?php echo $forum-&gt;getDescription() ?&gt;&lt;/h3&gt;<br />
</code><code><br />
&lt;?php if (count($childs) &gt; 0): ?&gt;<br />
&lt;h2&gt;Sub Forums:&lt;/h2&gt;<br />
&lt;ul&gt;<br />
</code><code><br />
&lt;?php foreach ($childs as $child): ?&gt;<br />
&lt;li&gt;&lt;?php echo link_to($child-&gt;getTitle(),'@view_forum_by_title?title='.$child-&gt;getTitle()) ?&gt;&lt;/li&gt;<br />
&lt;?php endforeach; ?&gt;<br />
</code><code><br />
&lt;/ul&gt;<br />
&lt;?php endif; ?&gt;<br />
</code><code><br />
&lt;h2&gt;Threads:&lt;/h2&gt;<br />
&lt;?php if (count($threads) &gt; 0): ?&gt;<br />
&lt;ul&gt;<br />
</code><code><br />
&lt;?php foreach ($threads as $thread): ?&gt;<br />
&lt;li&gt;&lt;?php echo link_to($thread-&gt;getTitle(),'@view_thread_by_title?id='.$thread-&gt;getID().'&amp;title='.$thread-&gt;getTitle()) ?&gt;&lt;/li&gt;<br />
&lt;?php endforeach; ?&gt;<br />
</code><code><br />
&lt;/ul&gt;<br />
&lt;?php if ($page &gt; 1): ?&gt;<br />
&lt;?php echo link_to('&lt; '.($page - 1).' &lt;', '@view_forum_by_title?id='.$forum-&gt;getID().'&amp;title='.$forum-&gt;getTitle().'&amp;page='.($page - 1), array ('class' =&gt; 'pager')) ?&gt;<br />
&lt;?php endif; ?&gt;<br />
</code><code><br />
&lt;?php if ($forum-&gt;getThreadsNumber() &gt; $limit): ?&gt;<br />
&lt;?php echo link_to('&gt; '.($page + 1).' &gt;', '@view_forum_by_title?id='.$forum-&gt;getID().'&amp;title='.$forum-&gt;getTitle().'&amp;page='.($page + 1), array ('class' =&gt; 'pager')) ?&gt;<br />
&lt;?php endif; ?&gt;<br />
</code><code><br />
&lt;?php else: ?&gt;<br />
</code><code><br />
&lt;h3&gt;No threads in this forum&lt;/h3&gt;<br />
&lt;?php endif; ?&gt;<br />
</code><code><br />
&lt;?php if ($sf_user-&gt;can('create_thread')): ?&gt;<br />
&lt;?php echo link_to('Create new Thread!','@new_thread_in_forum?id='.$forum-&gt;getID().'&amp;title='.$forum-&gt;getTitle()) ?&gt;<br />
&lt;?php endif; ?&gt;<br />
</code><br />
Ripeto che comunque è un work in progress, modifico il progetto ogni giorno quindi è soggetto a modifiche. Alla fine di questi post su symfony renderò disponibile la versione finale.</p>
<p>Da notare come le variabili che nel controller sono nella forma $this-&gt;variabile nella view sono semplicemente $variabile.<br />
Per il resto faccio notare che i metodi $forum-&gt;getPath() e $user-&gt;can(&#8216;create_thread&#8217;) sono definite da me rispettivamente in lib/model/Forum.php e apps/frontend/lib/myUser.class.php. Le vedremo meglio in seguito, per ora sappiate che servono per ottenere il percorso in cui è il forum, partendo la forum id#1, passando per i figli, mentre la seconda gestisce i permessi dell&#8217;utente corrente (o nessun utente, nel caso non sia loggato).</p>
<p>Questa è la vista legata alla singola azione, ma c&#8217;è altro. Ogni applicazione in symfony ha un layout definito in apps/*/config/view.yml. Apriamolo e si presenterà cosi:<br />
<code><br />
default:<br />
http_metas:<br />
content-type: text/html<br />
</code><code><br />
metas:<br />
title:        Shiny!<br />
#description:  symfony project<br />
#keywords:     symfony, project<br />
#language:     en<br />
robots:       index, follow<br />
</code><code><br />
stylesheets:    [main, default, my]<br />
</code><code><br />
javascripts:    []<br />
</code><code><br />
has_layout:     on<br />
layout:         layout&lt;/pre&gt;<br />
</code><br />
has_layout specifica che l&#8217;applicazione ha un template generale, mentre la criptica riga seguente layout: layout dice a symfony che il layout dell&#8217;applicazione avrà nome layout.php, nella cartella apps/*/templates/.</p>
<p>Ed ora vediamolo, il nostro layout.php:<br />
<code><br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;?php include_http_metas() ?&gt;<br />
&lt;?php include_metas() ?&gt;<br />
&lt;?php include_title() ?&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;!-- start header --&gt;<br />
&lt;div id="header"&gt;<br />
&lt;div id="logo"&gt;<br />
&lt;h1&gt;&lt;?php echo link_to('Shiny!','@homepage') ?&gt;&lt;/h1&gt;<br />
&lt;p&gt;Built with &lt;?php echo link_to('symfony 1.1','http://www.symfony-project.org') ?&gt;&lt;/p&gt;<br />
&lt;/div&gt;<br />
&lt;div id="search"&gt;<br />
&lt;form method="post" action="&lt;?php echo url_for('forum/search') ?&gt;"&gt;<br />
&lt;fieldset&gt;<br />
&lt;input id="s" type="text" name="s" value="" class="text" /&gt;<br />
&lt;input id="x" type="submit" value="Search" class="button" /&gt;<br />
&lt;/fieldset&gt;<br />
&lt;/form&gt;<br />
&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;!-- end header --&gt;<br />
&lt;!-- start page --&gt;<br />
&lt;div id="page"&gt;<br />
&lt;!-- start content --&gt;<br />
&lt;div id="content"&gt;<br />
&lt;?php echo $sf_content ?&gt;<br />
&lt;/div&gt;<br />
&lt;!-- end content --&gt;<br />
&lt;!-- start sidebar --&gt;<br />
&lt;div id="sidebar"&gt;<br />
&lt;ul&gt;<br />
&lt;li&gt;<br />
&lt;h2&gt;&lt;?php echo (($sf_user-&gt;isLogged()) ? $sf_user-&gt;getName() : 'User') ?&gt; Menu&lt;/h2&gt;<br />
&lt;ul&gt;<br />
&lt;?php if($sf_user-&gt;isLogged()): ?&gt;&lt;li&gt;&lt;?php echo link_to('Control Panel','@user_control_panel') ?&gt;&lt;/li&gt;<br />
&lt;li&gt;&lt;?php echo link_to('Logout','@user_logout') ?&gt;&lt;/li&gt;<br />
&lt;?php else: ?&gt;&lt;li&gt;&lt;?php echo link_to('Login','@user_login') ?&gt;&lt;/li&gt;<br />
&lt;li&gt;&lt;?php echo link_to('Register','@user_registration') ?&gt;&lt;/li&gt;<br />
&lt;?php endif; ?&gt;&lt;/ul&gt;<br />
&lt;/li&gt;<br />
&lt;li&gt;<br />
&lt;h2&gt;Misc&lt;/h2&gt;<br />
&lt;ul&gt;<br />
&lt;li&gt;&lt;?php echo link_to('Advanced search','@advanced_search') ?&gt;&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;/div&gt;<br />
&lt;!-- end sidebar --&gt;<br />
&lt;div class="clearer"&gt; &lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;!-- end page --&gt;<br />
&lt;!-- start footer --&gt;<br />
&lt;div id="footer"&gt;<br />
&lt;p&gt;©2008 All Rights Reserved.  • &lt;/a&gt;&lt;/p&gt;<br />
&lt;/div&gt;<br />
&lt;!-- end footer --&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
</code><br />
Tralasciando la struttura fatta di div per l&#8217;aspetto grafico per l&#8217;applicazione, sottolineo come $sf_content contenga il risultato dell&#8217;elaborazione del template per il resto sono altre funzioni semplici come quelle definite su $sf_user, che come detto tratterò in seguito.</p>
<p>Ora spiego la funzione link_to(), utilizzata più volte: il primo parametro è il testo che apparirà nel link, il secondo è la destinazione del link. Se è una stringa come quelle utilizzate da me, preceduta dal simbolo @, allora symfony cercherà la regola con quel nome definita nel file di routing, altrimenti accetterà un valore del tipo &#8220;modulo/azione&#8221;, con eventuali parametri nella classica forma &#8220;?parametro=valore&amp;parametro2=valore2&#8243;. Inoltre link_to ha un terzo parametro facoltativo, che è un array associativo dove possiamo definire ad esempio classe, id ed altre proprietà del link. Funziona cosi:<br />
<code><br />
&lt;?php echo link_to('Questo è un link', 'modulo/azione?parametro1=valore1&amp;parametro2=valore2', array('class' =&gt; 'classe1', 'id' =&gt; 'id1')) ?&gt;<br />
</code><br />
Per oggi è tutto, alla prossima!</p>
]]></content:encoded>
			<wfw:commentRss>http://phpblog.it/2008/06/11/symfony-le-viste/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>symfony: moduli e azioni</title>
		<link>http://phpblog.it/2008/06/04/symfony-moduli-e-azioni/</link>
		<comments>http://phpblog.it/2008/06/04/symfony-moduli-e-azioni/#comments</comments>
		<pubDate>Wed, 04 Jun 2008 05:00:13 +0000</pubDate>
		<dc:creator>Davide Borsatto</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[shiny]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://phpblog.it/2008/06/04/symfony-moduli-e-azioni/</guid>
		<description><![CDATA[Questa volta si inizia davvero con il codice PHP. Passiamo quindi realmente alla pratica dopo le prime puntate di introduzione del progetto. Iniziamo generando tre moduli per la nostra applicazione frontend: php symfony generate:module frontend forum php symfony generate:module frontend thread php symfony generate:module frontend user Questo creerà tre directory all&#8217;interno di apps/frontend/modules/, contenenti a [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://172.18.0.13/wordpress/wp-content/uploads/2008/06/symfony.jpg" alt="Symfony" />Questa volta si inizia davvero con il codice PHP. Passiamo quindi realmente alla pratica dopo le prime puntate di introduzione del progetto.</p>
<p><span id="more-130"></span></p>
<p>Iniziamo generando tre moduli per la nostra applicazione frontend:</p>
<pre>
php symfony generate:module frontend forum
php symfony generate:module frontend thread
php symfony generate:module frontend user</pre>
<p>Questo creerà tre directory all&#8217;interno di <code>apps/frontend/modules/</code>, contenenti a loro volta le cartelle <code>template</code> e <code>actions</code>.</p>
<p>Ora apriamo il file <code>apps/frontend/config/routing.yml</code> e modifichiamolo per renderlo come segue:</p>
<pre>
homepage:
  url:   /
  param: { module: forum, action: index }

view_forum_by_id:
  url:   /view-forum/:id
  param: { module: forum, action: viewById }
  requirements: { id: \d+ }

view_forum_by_title:
  url:   /view-forum/:title
  param: { module: forum, action: viewByTitle }</pre>
<p>Questo file spiega le regole di routing che la nostra applicazione dovrà seguire. Ad ogni regola corrisponde un nome (<em>hompage</em>, <em>view_forum_by_id</em>, e <em>view_forum_by_title</em>) seguita da un pattern per l&#8217;url a cui la regola dovrà sottostare, dai parametri della regola, ed eventualmente da dei requisiti a cui i parametri devono corrispondere.<br />
Prendiamo per esempio la regola <code>view_forum_by_id</code>: deve avere un url che &#8220;<em>matchi</em>&#8221; il pattern <code>/view-forum/:id</code>, ovvero deve iniziare con uno slash, la stringa <em>view-forum</em>, un altro slash e una variabile <em>id</em> (distinta dai due punti <strong>:</strong>). Nella sezione param indichiamo che nel caso l&#8217;url corrisponda a questa regola, symfony deve richiamare il modulo <strong>forum</strong> e l&#8217;azione <strong>viewById</strong>.<br />
Con requirements poi, restringiamo il valore di <code>id</code> ai soli interi, tramite la notazione \d+ (vedasi espressioni regolari).</p>
<p>Le regole sono in ordine di priorità, quindi la prima che combacia con l&#8217;url richiesto sarà quella applicata.<br />
Per questo è opportuno lasciare alla fine del file le regole predefinite</p>
<pre>
default_symfony:
  url:   /symfony/:action/*
  param: { module: default }

default_index:
  url:   /:module
  param: { action: index }

default:
  url:   /:module/:action/*</pre>
<p>In modo che in ogni caso di trovi qualche corrispondenza.</p>
<p>Ora modifichiamo il file <code>apps/frontend/modules/forum/actions/actions.class.php</code>, cerchiamo il metodo <code>executeIndex</code> e al posto del forward pre-inserito scriviamo noi questo:</p>
<pre>
  $this-&gt;redirect('@view_forum_by_id?id=1');</pre>
<p>In questo modo effettuiamo un redirect, con destinazione la regola view_forum_by_id<code> (specificata dalla presenza della @ prima del nome), assegnando ad id il valore 1. Il forum con id 1 è quello pre-definito, che è padre di tutti i sotto-forum.</code></p>
<p>Andiamo ora oltre, e aggiungiamo i seguenti metodi:</p>
<pre>
public function executeViewByID()
{
    // Retrieves data using the forum id
    $forumID = $this-&gt;getRequest()-&gt;hasParameter('id') ? $this-&gt;getRequest()-&gt;getParameter('id') : 1;
    $this-&gt;forum = ForumPeer::retrieveByPk($forumID);
    $this-&gt;forward404Unless($this-&gt;forum);

    $this-&gt;findData($forumID);

    // Set a common template
    $this-&gt;setTemplate('view');
}
public function executeViewByTitle()
{
    // Retrieves data using the forum title
    $forumTitle = $this-&gt;getRequest()-&gt;hasParameter('title') ? $this-&gt;getRequest()-&gt;getParameter('title') : 'Main';
    $c = new Criteria();
    $c-&gt;add(ForumPeer::TITLE, $forumTitle);
    $this-&gt;forum = ForumPeer::doSelectOne($c);
    $this-&gt;forward404Unless($this-&gt;forum);
    $forumID = $this-&gt;forum-&gt;getId();

    // Executes a common function for addictional infos
    $this-&gt;findData($forumID);

    // Set a common template
    $this-&gt;setTemplate('view');
}
private function findData($forumID)
{
    $c = new Criteria();
    $c-&gt;add(ForumPeer::PARENT_ID, $forumID);
    $this-&gt;childs = ForumPeer::doSelect($c);
    $c = new Criteria();
    $c-&gt;add(ThreadPeer::FORUM_ID, $forumID);
    $this-&gt;threads = ThreadPeer::doSelect($c);
}</pre>
<p>In symfony i metodi che iniziano con <strong>execute</strong>, e sono seguiti da un nome (la cui prima lettera maiuscola) sono delle azioni richiamabili dal browser. In questo caso executeViewByID ed executeViewByTitle sono due azioni valide, mentre findData è un metodo richiamato dai due per eseguire del codice in comune, quindi non è un azione, e lo si dichiara privato e senza la keyword execute.</p>
<p>Ora andiamo a vedere nel dettaglio ciò che accade nelle azioni:</p>
<pre>
1    $forumID = $this-&gt;getRequest()-&gt;hasParameter('id') ? $this-&gt;getRequest()-&gt;getParameter('id') : 1;
2    $this-&gt;forum = ForumPeer::retrieveByPk($forumID);
3    $this-&gt;forward404Unless($this-&gt;forum);

4    $this-&gt;findData($forumID);

5    $this-&gt;setTemplate('view');</pre>
<p>Riga 1<br />
Espressione ternaria: se l&#8217;oggetto <code>request</code> ha il parametro id, allora assegniamo a $forumID quel valore, altrimenti assegniamo 1 (il valore di default).<br />
Riga 2<br />
A $this-&gt;forum assegniamo il risultato della ricerca tramite chiave primaria (metodo statico retrieveByPk, ovvero Primary Key) con valore $forumID sull&#8217;oggetto ForumPeer, ovvero la rappresentazione della tabella (l&#8217;oggetto Forum, a cui appartiene $this-&gt;forum è la rappresentazione della singola tupla).<br />
Riga 3<br />
Redirezioniamo l&#8217;elaborazione ad una pagina di 404 a meno che $this-&gt;forum non abbia un valore valido.<br />
Riga 4<br />
Richiamiamo il metodo findData, che esegue un&#8217;elaborazione in comune ai due viewBy*.<br />
Riga 5<br />
I due viewBy* utilizzando lo stesso template, quindi tramite questa istruzione assegno a quest&#8217;azione il template view.</p>
<p>Ora nel metodo privato findData</p>
<pre>
1    $c = new Criteria();
2    $c-&gt;add(ForumPeer::PARENT_ID, $forumID);
3    $this-&gt;childs = ForumPeer::doSelect($c);
4    $c = new Criteria();
5    $c-&gt;add(ThreadPeer::FORUM_ID, $forumID);
6    $this-&gt;threads = ThreadPeer::doSelect($c);</pre>
<p>Riga 1<br />
Creiamo una nuova istanza della classe <code>Criteria</code>, ovvero la classe utilizzata per realizzare le query.<br />
Riga 2<br />
Specifichiamo che il valore di forums.parent_id (rappresentato dalla costante ForumPeer::PARENT_ID) deve valere $forumID<br />
Riga 3<br />
All&#8217;array $this-&gt;childs assegniamo tutte le corrispondenze della query preparata<br />
Riga 4,5,6<br />
Stesso significato delle precedenti, solo che al posto di ottenere i forum &#8220;figli&#8221; ottengo i thread appartenenti a quel forum</p>
<p>Oggi abbiamo visto le azioni di base, la prossima volta (per non appesantire troppo il post) vedremo il template associato a queste azioni, più alcune cose sulla gestione dell&#8217;utente.<br />
Per eventuali dubbi ci sono i commenti, sarò felice di rispondere, quindi non siate timidi. <img src='http://phpblog.it/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Alla prossima!</p>
]]></content:encoded>
			<wfw:commentRss>http://phpblog.it/2008/06/04/symfony-moduli-e-azioni/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>symfony: back in action!</title>
		<link>http://phpblog.it/2008/05/26/symfony-back-in-action/</link>
		<comments>http://phpblog.it/2008/05/26/symfony-back-in-action/#comments</comments>
		<pubDate>Mon, 26 May 2008 05:00:01 +0000</pubDate>
		<dc:creator>Davide Borsatto</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[shiny]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://phpblog.it/2008/05/26/symfony-back-in-action/</guid>
		<description><![CDATA[Dopo qualche giorno di pausa forzata dovuta ad impegni, torna più prepotente che mai il nostro caro vecchio symfony! Finalmente! Dopo le prime puntate dove ci siamo occupati più che altro di teoria, ora è giunto il momento di vedere davvero del codice PHP. Anzi, prima di fare ciò dobbiamo dedicarci un attimo al database. [...]]]></description>
			<content:encoded><![CDATA[<p>Dopo qualche giorno di pausa forzata dovuta ad impegni, torna più prepotente che mai il nostro caro vecchio <strong>symfony</strong>!</p>
<p><span id="more-122"></span>Finalmente! Dopo le prime puntate dove ci siamo occupati più che altro di teoria, ora è giunto il momento di vedere davvero del codice PHP.</p>
<p>Anzi, prima di fare ciò dobbiamo dedicarci un attimo al database. Come ho accennato, questo nostro progetto ci porterà alla realizzazione di un forum, che ho affettuosamente chiamato &#8220;<em>shiny!</em>&#8220;. Ora, abbiamo bisogno di definire concretamente questo forum, per poterci lavorare sopra. Per poter utilizzare un database in symfony, è necessario descrivere la struttura delle tabelle attraverso il file <strong>config/schema.yml</strong>. Ecco quello che utilizzo io:</p>
<pre>
propel:
  groups:
    _attributes: { phpName: Group }
    id:          ~
    name:        varchar(50)
  authors:
    _attributes: { phpName: Author }
    id:          ~
    group_id:    { foreignTable: groups, foreignReference: id }
    name:        varchar(50)
    password:    varchar(50)
    image:       varchar(255)
    signature:   varchar(255)
    advises:     integer
    created_on:  timestamp
  forums:
    _attributes: { phpName: Forum }
    id:          ~
    title:       varchar(50)
    description: varchar(255)
    parent_id:   { foreignTable: forums, foreignReference: id }
  threads:
    _attributes: { phpName: Thread }
    id:          ~
    forum_id:    { foreignTable: forums, foreignReference: id }
    author_id:   { foreignTable: authors, foreignReference: id }
    created_on:  timestamp
    title:       varchar(50)
  posts:
    _attributes: { phpName: Post }
    id:          ~
    author_id:   { foreignTable: authors, foreignReference: id }
    thread_id:   { foreignTable: threads, foreignReference: id }
    created_on:  timestamp
    updated_on: timestamp
    text:        longvarchar</pre>
<p>Chiarimento rapido. YAML è un linguaggio di markup dalla sintassi più coincisa rispetto ad XML, che si basa sull&#8217;indentazione con gli spazi (niente tab quindi). Per ulteriori informazioni potete visitare <a href="http://www.yaml.org/start.html">la pagina ufficiale del progetto</a>.</p>
<p>Ora analizziamo per bene ciò che ho appena scritto: L&#8217;elemento &#8220;<em>propel:</em>&#8221; è il padre di tutti gli altri, e deve esserci forzatamente su utilizzate questo ORM (che è il default plugin di symfony). Ogni figlio di propel è il nome con cui la tabella è salvata nel DBMS, seguita dall&#8217;elemento <em>_attributes</em>; Tra le parentesi graffe l&#8217;elemento <strong>phpName</strong> indica il nome che avrà la classe generata in PHP (per convenzione singolare con la prima lettera maiuscola). Di seguito poi ogni elemento delle tabelle, dove <strong>id: ~</strong> significa chiave primaria. Gli altri elementi credo che siano comprensibili, per cui non mi dilungo tanto nella spiegazione. In caso di dubbi scriveteli pure nei commenti.</p>
<p>Ora da linea di comando date questi comandi:</p>
<pre>php symfony propel:build-model
php symfony propel:build-forms</pre>
<p>Seguiti da:</p>
<pre>php symfony propel:build-sql</pre>
<p>E troverete il file sql generato per la creazione del nostro database all&#8217;interno della directory data/sql sotto il nome di lib.model.schema.sql.<br />
Siccome probabilmente questo file non sarà al 100% corretto e pronto all&#8217;inserimento, vi consiglio di aprilo e correggerlo a mano, usandolo solo come base.<br />
Ultima cosa prima di partire sarà modificare il file config/databases.yml e trasformarlo nel seguente:</p>
<pre>
all:
  propel:
  class:  sfPropelDatabase
  param:
  dsn: mysql://user:password@localhost/database</pre>
<p>Ovviamente adattando user, password e database alla vostra situazione.<br />
Con la configurazione abbiamo finito, la prossima volta realizzeremo i <strong>controller</strong> della nostra applicazione. Alla prossima!</p>
]]></content:encoded>
			<wfw:commentRss>http://phpblog.it/2008/05/26/symfony-back-in-action/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

