Advanced symfony Techniques
Upcoming SlideShare
Loading in...5
×
 

Advanced symfony Techniques

on

  • 13,546 views

Go beyond the documentation and explore some of what's possible if you stretch symfony to its limits. We will look at a number of aspects of symfony 1.4 and Doctrine 1.2 and tease out some powerful ...

Go beyond the documentation and explore some of what's possible if you stretch symfony to its limits. We will look at a number of aspects of symfony 1.4 and Doctrine 1.2 and tease out some powerful functionality you may not have expected to find, but will doubtless be able to use. Topics covered will include routing, forms, the config cache and record listeners. If you're comfortable in symfony and wondering what's next, this session is for you.

Statistics

Views

Total Views
13,546
Views on SlideShare
12,353
Embed Views
1,193

Actions

Likes
25
Downloads
237
Comments
0

23 Embeds 1,193

http://www.symfonylab.com 568
http://www.symfony.es 192
http://www.charnad.com 127
http://test.ical.ly 103
http://www.jpgranja.com 55
http://www.ausgebloggt.de 35
http://www.testically.org 21
http://www.techgig.com 17
http://feeds2.feedburner.com 16
http://floeh.com 13
http://www.sfexception.com 7
http://feeds.feedburner.com 7
http://theoldreader.com 5
http://kirugan.ru 5
http://symfony.lab216.com 4
http://static.slidesharecdn.com 4
http://dashboard.bloglines.com 4
http://xss.yandex.net 2
http://dev.symfony2developer.com 2
http://115.112.206.131 2
http://symfony2developer.com 2
http://www.inoreader.com 1
http://www.thewebhatesme.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Advanced symfony Techniques Advanced symfony Techniques Presentation Transcript

  • Advanced symfony Techniques Kris Wallsmith
  • @kriswallsmith • Release Manager for symfony 1.3 & 1.4 • On Symfony and Doctrine teams • Senior Software Engineer at • 10 years experience with PHP and web development • Open source evangelist and international speaker • Hopeless plugin developer…
  • • DbFinderPlugin • sfPropelActAsPolymorphicBehaviorPlugin • sfControlPanelPlugin • sfSimpleBlogPlugin • sfDoctrineDynamicFormRelationsPlugin • sfSimpleCMSPlugin • sfDoctrineMasterSlavePlugin • sfSimpleForumPlugin • sfFeed2Plugin • sfSpyPlugin • sfFormYamlEnhancementsPlugin • sfSslRequirementPlugin • sfGoogleAnalyticsPlugin • sfStatsPlugin • sfGoogleWebsiteOptimizerPlugin • sfTaskExtraPlugin • sfModerationPlugin • sfWebBrowserPlugin • sfPagerNavigationPlugin
  • Please see me if you want to help with or take over a plugin's maintenance. Lots to choose from!
  • #phpmatsuri October 2-3, 2010 Tokyo
  • #phpmatsuri • Around 90 attendees • CakePHP, Symfony, & Lithium were represented • Most folks were CakePHP users • CakePHP documentation was translated early, so… • Please help translate Symfony2 & Doctrine2 documentation!
  • CAUTION PSEUDO CODE AHEAD
  • Host Aware Routing
  • domain.com
  • foobar.domain.com
  • barfoo.domain.com
  • homepage: url: / param: { module: main, action: indexOrDash }
  • homepage: url: / param: { module: main, action: indexOrDash } if (preg_match('/.../', $r->getHost(), $m))
  • class sfRoute • ->matchesUrl(...) Does the supplied URL match this route? GET / HTTP/1.0 Host: foobar.domain.com
  • class sfRoute Ver y slow • ->matchesUrl(...) url_for('main/dashboard?username=foobar') Does the supplied URL match this route? • ->matchesParameters(...) Do the supplied parameters match this route?
  • class sfRoute • ->matchesUrl(...) Does the supplied URL match this route? • ->matchesParameters(...) url_for('@dashboard?username=foobar') Do the supplied parameters match this route? • ->generate(...) Generate a URL using this route and these parameters.
  • ->matchesUrl(...) • $url The current URI • $context An array of contextual information, including the current host • Returns false or an array of parameters extracted from the URI
  • ->matchesParameters(...) • $params An associative array of parameter names and values • $context An array of contextual information, including the current host • Returns true or false
  • ->generate(...) • $params An associative array of parameter names and values • $context An array of contextual information, including the current host • $absolute Whether to generate an absolute URL • Returns the generated URL
  • Process the host string with a second, internal route
  • public function __construct(...) { list($host, $pattern) = explode('/', $pattern, 2); $hostRoute = $this->createHostRoute($host, ...); parent::__construct(...); }
  • public function matchesUrl($url, $c) { // check parent::matchesUrl() first $hp = $hostRoute->matchesUrl('/'.$c['host'], $c); // include host parameters in return }
  • public function matchesParameters($p, $c) { $hp = $this->extractHostParams($p); return parent::matchesParameters($p, $c) && $hostRoute->matchesParameters($hp, $c); }
  • public function generate($p, $c, $abs) { $hp = $this->extractHostParams($p); // protocol, prefix... $host = $hostRoute->generate($hp, $c, false); $uri = parent::generate($p, $c, false); return $protocol.':/'.$host.$prefix.$uri; }
  • homepage: url: / param: { module: main, action: indexOrDash }
  • Hard co d homepage: e d F TL url: domain.com/ :( class: sfHostAwareRoute param: { module: main, action: index } dashboard: url: :username.domain.com/ class: sfHostAwareRoute param: { module: main, action: dashboard }
  • homepage: url: %APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: index } dashboard: url: :username.%APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: dashboard }
  • Custom Config Handler
  • class sfHostAwareRoutingConfigHandler extends sfRoutingConfigHandler { protected function parse($configFiles) { return array_map( array($this, 'filterRoute'), parent::parse($configFiles) ); } // ... }
  • FTW! Free protected function filterRoute($route) { list($class, $args) = $route; $args[0] = $this->replaceConstants($args[0]); return array($class, $args); }
  • # config_handlers.yml config/routing.yml: class: sfHostAwareRoutingConfigHandler file: %SF_LIB_DIR%/sfHostAwareRout...
  • sfHostAwareRoutingPlugin Add subdomains to your routing rules.
  • Graceful POST Authentication
  • An example…
  • CENSORED CENSORED
  • W here's my blog pos t!? ! AIL F
  • Extend the security filter
  • class GracefulSecurityFilter extends sfBasicSecurityFilter { protected function forwardToLoginAction() { // stash the interrupted request $attr->add(array( 'module' => $context->getActionName(), 'action' => $context->getModuleName(), 'method' => $request->getMethod(), 'params' => $requestParams->getAll(), ), 'stash'); parent::forwardToLoginAction(); } }
  • # filters.yml security: class: GracefulSecurityFilter
  • Replay the stashed request after login
  • // called after authentication protected function replayStashedRequest() { if ($s = $attr->removeNamespace('stash')) { $request->setMethod($s['method']); $params->clear(); $params->add($s['params']); $this->forward($s['module'], $s['action']); } }
  • Extra Security
  • An example…
  • # security.yml acceptInvitation: is_secure: true extra_credentials: account: { lifetime: 300 }
  • Events to the rescue!
  • controller.change_action
  • // connect to the event $ed->connect('controller.change_action', $cb)
  • // check security.yml $action->getSecurityValue('extra_credentials')
  • // check current user $u->getAttribute('extra_credentials', array())
  • // remove any expired credentials $now = time(); foreach ($creds as $name => $attr) { if ($now > $attr['expires_at']) { unset($creds[$name]); } }
  • // stash credentials and referer $u->setAttribute('challenge_credentials', ...) $u->setAttribute('challenge_referer', ...)
  • // forward to challenge form $controller->forward('security', 'challenge') throw new sfStopException();
  • // add the granted credentials $now = time(); foreach ($new as $name => $attr) { $creds[$name] = array( 'expires_at' => $now + $attr['lifetime'], ); } $u->setAttribute('extra_credentials', $creds);
  • // send them on their way $this->redirect($referer);
  • sfExtraSecurityPlugin Re-prompt your users for authentication.
  • Javascript Compression
  • <script src="http://domain.com/widget.js"></script>
  • class jsActions extends sfActions { public function executeWidget(sfWebRequest $req) { $this->lightbox = $req->hasParameter('lb'); $this->debug = $req->hasParameter('debug'); } }
  • <?php if ($debug): ?> console.log("embedding mootools"); <?php endif; ?> var e = document.createElement("script"); e.src = "<?php echo public_path('js/moo.js', true) ?>"; e.async = true; document.body.appendChild(e); // etc...
  • Custom View Class
  • # module.yml all: view_class: Javascript JavascriptView
  • class JavascriptView extends sfPHPView { public function render() { return $this->compress(parent::render()); } protected function compress() { // ... } }
  • $i = tempnam(sys_get_temp_dir(), __CLASS__); $o = tempnam(sys_get_temp_dir(), __CLASS__); file_put_contents($i, $content); shell_exec(vsprintf( 'java -jar %s --type js -o %s %s', array_map('escapeshellarg', array($yui, $o, $i)) )); return file_get_contents($o);
  • Standard Caching
  • # cache.yml widget: enabled: true with_layout: true
  • developer.yahoo.com/yui/compressor/
  • A Few Apache Tricks
  • rm web/.htaccess
  • AllowOverride None
  • <Directory /path/to/web> Include /path/to/.htaccess </Directory>
  • Core Assets
  • Missing Asset s #FAIL :(
  • AliasMatch /sf/(.*) /path/to/symfony/data/web/sf/$1 AliasMatch /sfDoctrinePlugin/(.*) /path/to/sfDoctrinePlugin/web/$1 NameVirtualHost *:80 <VirtualHost _default_:80> # ...
  • Assets Fo u nd FTW!
  • The Dreaded Trailing Slash…
  • AIL #F
  • RewriteEngine On RewriteRule ^(.*)/$ /$1 [R=301,L]
  • GET /about/ HTTP/1.1 Host: domain.com HTTP/1.1 301 Moved Permanently Location: http://domain.com/about
  • Embedded Forms
  • Book One book has many authors, Authors one author has many books. Person
  • Book: columns: title: string(255) relations: authors: { class: Person, refClass: BookAuthor } BookAuthor: columns: book_id: integer author_id: integer relations: book: { local: book_id } author: { class: Person, local: author_id } Person: columns: name: string(255)
  • // embed related forms $this->embedRelation('authors'); unset($this['authors_list']);
  • // embed related forms dynamically! $this->embedDynamicRelation('authors');
  • form.method_not_found form.filter_values
  • // called when a form is configured public function embedDynamicRelation($name) { $rel = $table->getRelation($name); $this->rels[] = $rel; $this->doEmbed($name, $obj->get($rel->getAlias())); }
  • // called when a form is bound public function filterValues(sfEvent $event, $values) { foreach ($this->rels as $rel) { $name = $rel->getName(); $this->doEmbed($name, $values[$name]); } $obj->addListener(new DeleteListener($form)); }
  • $parent = new BaseForm(); foreach ($values as $i => $value) { if (is_object($value)) { // create form with object } elseif ($value['id']) { // find previously embedded form } else { // create a new form } $parent->embedForm($i, $child); } $form->embedForm($rel->getName(), $parent);
  • // extract existing objects from embedded forms // and compare to the current object collection public function preSave(Doctrine_Event $event) { foreach ($coll as $i => $obj) { $pos = array_search($obj, $existing, true); if (false === $pos) $coll->remove($i); if ($column['notnull']) $obj->delete(); } }
  • sfDoctrineDynamicFormRelationsPlugin Common sense embedded forms.
  • Questions? • Host aware routing • Graceful POST authentication • Extra security • Javascript compression • Apache tricks • Embedded forms
  • OpenSky is Hiring! http://engineering.shopopensky.com Please contact me if you're interested.
  • Thank you!