Be Restful: Fabien Potencier
Be Restful: Fabien Potencier
Fabien Potencier
symfony 1.2 is
REST compliant
out of the box
symfony 1.2 supports
GET
POST
HEAD
PUT
DELETE
To simulate PUT or DELETE
from a browser, symfony
uses a special parameter
sf_method
<form action="#" method="POST">
<input type="hidden" name="sf_method" value="PUT" />
$b = new sfBrowser();
$b->
click('/delete', array(), array('method' => 'delete'))->
// ...
;
$form->renderFormTag('@article_update',
array('method' => 'PUT')
)
// or
// ...
}
# apps/frontend/config/routing.yml
article_update:
url: /article/:id/update
param: { module: article, action: update }
class: sfRequestRoute
requirements: { sf_method: PUT }
# apps/frontend/config/routing.yml
article_update:
url: /article/:id
param: { module: article, action: update }
class: sfRequestRoute
requirements: { sf_method: PUT }
article_show:
url: /article/:id
param: { module: article, action: show }
class: sfRequestRoute
requirements: { sf_method: GET }
Routes are
first-class objects
in symfony 1.2
sfRoute
The route object
embarks all the logic
to match a URL
to generate a URL
The route context
sfDomainRoute
Some websites have URLs like
http://USERNAME.example.com/...
user_homepage:
url: /user
class: sfDomainRoute
params: { module: user, action: index }
$retval[1]['username'] = $this->getSubdomain($context);
return $retval;
}
return $parts[0];
}
}
echo url_for('@user_homepage');
// generates /user
echo url_for('@user_homepage?username=foo');
return $protocol.'://'.$host;
}
$routing = $this->getContext()->getRouting();
echo $routing->generate('user_homepage');
$subdomain = $this->getSubdomain($context);
if (is_null($object = $this->getObject($subdomain)))
{
$message = sprintf('Unable to find the "user" object with the following
subdomain "%s".', $subdomain);
throw new sfError404Exception($message);
}
$retval[1]['user'] = $object;
return $retval;
}
if (!isset($this->options['method']))
{
throw new InvalidArgumentException('You must pass a "method".');
}
return call_user_func(
array($this->options['model'], $this->options['method']),
$subdomain
);
}
A URL is the representation
of a resource
sfRoute
sfRequestRoute
sfObjectRoute
sfPropelRoute
sfPropelRoute
binds a URL
to a Propel resource
articles:
url: /articles
params: { module: article, action: list }
class: sfPropelRoute
options: { model: Article, list: articles }
return self::doSelectOne($criteria);
}
}
article:
url: /article/:id-:slug
params: { module: article, action: show }
class: sfPropelRoute
options:
model: Article
method: retrieveOnlineByPk
object: article
allow_empty: false
segment_separators: [/, ., -]
url_for('@article?id='.$article->getId().'&slug='.$article
->getSlug()
url_for('article', $article)
sfRouteCollection
sfObjectRouteCollection
sfPropelRouteCollection
articles:
class: sfPropelRouteCollection
options: { model: Article }
~/work/tmp $ ./symfony app:routes frontend
Name articles_update
Pattern /articles/:id.:sf_format
Class sfPropelRoute
Defaults module: 'foo'
action: 'update'
sf_format: 'html'
Requirements id: '\\d+'
sf_method: 'put'
sf_format: '[^/\\.]+'
Options suffix: ''
variable_prefixes: array (0 => ':',)
segment_separators: array (0 => '/',1 => '.',)
variable_regex: '[\\w\\d_]+'
generate_shortest_url: true
extra_parameters_as_query_string: true
model: 'AdcArticlePeer'
object: 'article'
object_model: 'AdcArticle'
variable_prefix_regex: '(?:\\:)'
segment_separators_regex: '(?:/|\\.)'
variable_content_regex: '[^/\\.]+'
Regex #^
/articles
/(?P<id>\d+)
(?:\.(?P<sf_format>[^/\.]+)
)?
$#x
Tokens separator array (0 => '/',)
text array (0 => 'articles',)
separator array (0 => '/',)
variable array (0 => ':id',1 => 'id',)
separator array (0 => '.',)
variable array (0 => ':sf_format',1 => 'sf_format',)
./symfony propel:generate-module-for-route frontend articles
class articlesActions extends sfActions
{
public function executeIndex($request) {}
$this->redirect('@articles');
}
public function executeCreate($request)
{
$this->form = new AdcArticleForm();
$this->processForm($request, $this->form);
$this->setTemplate('new');
}
$this->processForm($request, $this->form);
$this->setTemplate('edit');
}
$this->redirect('@articles_edit?id='.$article->getId());
}
}
articles:
class: sfPropelRouteCollection
options:
model: Article
plural: articles
singular: article
actions: [list, show, edit, update]
module: articles
column: slug
# ...
form_tag_for($form, '@articles')
Contact
Fabien Potencier
[email protected]
http://www.sensiolabs.com/ http://www.symfony-project.org/