advanced symfony techniques

106
Advanced symfony Techniques Kris Wallsmith

Upload: kris-wallsmith

Post on 15-Jan-2015

12.734 views

Category:

Technology


2 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Advanced symfony Techniques

Advanced symfony TechniquesKris Wallsmith

Page 2: Advanced symfony Techniques

@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…

Page 3: Advanced symfony Techniques

• DbFinderPlugin

• sfControlPanelPlugin

• sfDoctrineDynamicFormRelationsPlugin

• sfDoctrineMasterSlavePlugin

• sfFeed2Plugin

• sfFormYamlEnhancementsPlugin

• sfGoogleAnalyticsPlugin

• sfGoogleWebsiteOptimizerPlugin

• sfModerationPlugin

• sfPagerNavigationPlugin

• sfPropelActAsPolymorphicBehaviorPlugin

• sfSimpleBlogPlugin

• sfSimpleCMSPlugin

• sfSimpleForumPlugin

• sfSpyPlugin

• sfSslRequirementPlugin

• sfStatsPlugin

• sfTaskExtraPlugin

• sfWebBrowserPlugin

Page 4: Advanced symfony Techniques

Please see me if you want tohelp with or take overa plugin's maintenance.

Lots to choose from!

Page 5: Advanced symfony Techniques

#phpmatsuriOctober 2-3, 2010

Tokyo

Page 6: Advanced symfony Techniques

• Around 90 attendees

• CakePHP, Symfony, & Lithiumwere represented

• Most folks were CakePHP users

• CakePHP documentation wastranslated early, so…

• Please help translate Symfony2 & Doctrine2 documentation!

#phpmatsuri

Page 7: Advanced symfony Techniques
Page 8: Advanced symfony Techniques

PSEUDO CODE AHEAD

CAUTION

Page 9: Advanced symfony Techniques

Host Aware Routing

Page 10: Advanced symfony Techniques

domain.com

Page 11: Advanced symfony Techniques

foobar.domain.com

Page 12: Advanced symfony Techniques

barfoo.domain.com

Page 13: Advanced symfony Techniques

homepage: url: / param: { module: main, action: indexOrDash }

Page 14: Advanced symfony Techniques

homepage: url: / param: { module: main, action: indexOrDash }

if (preg_match('/.../', $r->getHost(), $m))

Page 15: Advanced symfony Techniques

• ->matchesUrl(...)Does the supplied URL match this route?

class sfRoute

GET / HTTP/1.0Host: foobar.domain.com

Page 16: Advanced symfony Techniques

• ->matchesUrl(...)Does the supplied URL match this route?

• ->matchesParameters(...)Do the supplied parameters match this route?

class sfRoute

url_for('main/dashboard?username=foobar')

Very slow

Page 17: Advanced symfony Techniques

• ->matchesUrl(...)Does the supplied URL match this route?

• ->matchesParameters(...)Do the supplied parameters match this route?

• ->generate(...)Generate a URL using this route and these parameters.

class sfRoute

url_for('@dashboard?username=foobar')

Page 18: Advanced symfony Techniques

->matchesUrl(...)

• $urlThe current URI

• $contextAn array of contextual information, including the current host

• Returns false or an array of parameters extracted from the URI

Page 19: Advanced symfony Techniques

->matchesParameters(...)

• $paramsAn associative array of parameter names and values

• $contextAn array of contextual information, including the current host

• Returns true or false

Page 20: Advanced symfony Techniques

->generate(...)

• $paramsAn associative array of parameter names and values

• $contextAn array of contextual information, including the current host

• $absoluteWhether to generate an absolute URL

• Returns the generated URL

Page 21: Advanced symfony Techniques

Process the host string with a second, internal route

Page 22: Advanced symfony Techniques

public function __construct(...){ list($host, $pattern) = explode('/', $pattern, 2);

$hostRoute = $this->createHostRoute($host, ...);

parent::__construct(...);}

Page 23: Advanced symfony Techniques

public function matchesUrl($url, $c){ // check parent::matchesUrl() first

$hp = $hostRoute->matchesUrl('/'.$c['host'], $c);

// include host parameters in return}

Page 24: Advanced symfony Techniques

public function matchesParameters($p, $c){ $hp = $this->extractHostParams($p);

return parent::matchesParameters($p, $c) && $hostRoute->matchesParameters($hp, $c);}

Page 25: Advanced symfony Techniques

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;}

Page 26: Advanced symfony Techniques

homepage: url: / param: { module: main, action: indexOrDash }

Page 27: Advanced symfony Techniques

Hardcoded FTL :(homepage: url: domain.com/ class: sfHostAwareRoute param: { module: main, action: index }

dashboard: url: :username.domain.com/ class: sfHostAwareRoute param: { module: main, action: dashboard }

Page 28: Advanced symfony Techniques

homepage: url: %APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: index }

dashboard: url: :username.%APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: dashboard }

Page 29: Advanced symfony Techniques

Custom Config Handler

Page 30: Advanced symfony Techniques

class sfHostAwareRoutingConfigHandler extends sfRoutingConfigHandler{ protected function parse($configFiles) { return array_map( array($this, 'filterRoute'), parent::parse($configFiles) ); }

// ...}

Page 31: Advanced symfony Techniques

protected function filterRoute($route){ list($class, $args) = $route;

$args[0] = $this->replaceConstants($args[0]);

return array($class, $args);}

Free FTW!

Page 32: Advanced symfony Techniques

# config_handlers.ymlconfig/routing.yml: class: sfHostAwareRoutingConfigHandler file: %SF_LIB_DIR%/sfHostAwareRout...

Page 33: Advanced symfony Techniques

sfHostAwareRoutingPluginAdd subdomains to your routing rules.

Page 34: Advanced symfony Techniques

Graceful POST Authentication

Page 35: Advanced symfony Techniques

An example…

Page 36: Advanced symfony Techniques
Page 37: Advanced symfony Techniques
Page 38: Advanced symfony Techniques

CENSORED

CENSORED

Page 39: Advanced symfony Techniques
Page 40: Advanced symfony Techniques

Where's my blog post!?!

#FAIL

Page 41: Advanced symfony Techniques

Extend the security filter

Page 42: Advanced symfony Techniques

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(); }}

Page 43: Advanced symfony Techniques

# filters.ymlsecurity: class: GracefulSecurityFilter

Page 44: Advanced symfony Techniques

Replay the stashed requestafter login

Page 45: Advanced symfony Techniques

// called after authenticationprotected function replayStashedRequest(){ if ($s = $attr->removeNamespace('stash')) { $request->setMethod($s['method']);

$params->clear(); $params->add($s['params']);

$this->forward($s['module'], $s['action']); }}

Page 46: Advanced symfony Techniques

Extra Security

Page 47: Advanced symfony Techniques

An example…

Page 48: Advanced symfony Techniques
Page 49: Advanced symfony Techniques
Page 50: Advanced symfony Techniques

# security.ymlacceptInvitation: is_secure: true extra_credentials: account: { lifetime: 300 }

Page 51: Advanced symfony Techniques

Events to the rescue!

Page 52: Advanced symfony Techniques

controller.change_action

Page 53: Advanced symfony Techniques

// connect to the event$ed->connect('controller.change_action', $cb)

Page 54: Advanced symfony Techniques

// check security.yml$action->getSecurityValue('extra_credentials')

Page 55: Advanced symfony Techniques

// check current user$u->getAttribute('extra_credentials', array())

Page 56: Advanced symfony Techniques

// remove any expired credentials$now = time();foreach ($creds as $name => $attr){ if ($now > $attr['expires_at']) { unset($creds[$name]); }}

Page 57: Advanced symfony Techniques

// stash credentials and referer$u->setAttribute('challenge_credentials', ...)$u->setAttribute('challenge_referer', ...)

Page 58: Advanced symfony Techniques

// forward to challenge form$controller->forward('security', 'challenge')throw new sfStopException();

Page 59: Advanced symfony Techniques

// add the granted credentials$now = time();foreach ($new as $name => $attr){ $creds[$name] = array( 'expires_at' => $now + $attr['lifetime'], );}$u->setAttribute('extra_credentials', $creds);

Page 60: Advanced symfony Techniques

// send them on their way$this->redirect($referer);

Page 61: Advanced symfony Techniques

sfExtraSecurityPluginRe-prompt your users for authentication.

Page 62: Advanced symfony Techniques

Javascript Compression

Page 63: Advanced symfony Techniques

<script src="http://domain.com/widget.js"></script>

Page 64: Advanced symfony Techniques

class jsActions extends sfActions{ public function executeWidget(sfWebRequest $req) { $this->lightbox = $req->hasParameter('lb'); $this->debug = $req->hasParameter('debug'); }}

Page 65: Advanced symfony Techniques

<?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...

Page 66: Advanced symfony Techniques

Custom View Class

Page 67: Advanced symfony Techniques

# module.ymlall: view_class: Javascript

JavascriptView

Page 68: Advanced symfony Techniques

class JavascriptView extends sfPHPView{ public function render() { return $this->compress(parent::render()); }

protected function compress() { // ... }}

Page 69: Advanced symfony Techniques

$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);

Page 70: Advanced symfony Techniques

Standard Caching

Page 71: Advanced symfony Techniques

# cache.ymlwidget: enabled: true with_layout: true

Page 72: Advanced symfony Techniques

developer.yahoo.com/yui/compressor/

Page 73: Advanced symfony Techniques

A Few Apache Tricks

Page 74: Advanced symfony Techniques

rm web/.htaccess

Page 75: Advanced symfony Techniques

AllowOverride None

Page 76: Advanced symfony Techniques

<Directory /path/to/web> Include /path/to/.htaccess</Directory>

Page 77: Advanced symfony Techniques

Core Assets

Page 78: Advanced symfony Techniques

Missing Assets #FAIL :(

Page 79: Advanced symfony Techniques

AliasMatch /sf/(.*) /path/to/symfony/data/web/sf/$1

AliasMatch /sfDoctrinePlugin/(.*) /path/to/sfDoctrinePlugin/web/$1

NameVirtualHost *:80<VirtualHost _default_:80> # ...

Page 80: Advanced symfony Techniques

Assets Found FTW!

Page 81: Advanced symfony Techniques

The Dreaded Trailing Slash…

Page 82: Advanced symfony Techniques
Page 83: Advanced symfony Techniques

#FAIL

Page 84: Advanced symfony Techniques

RewriteEngine OnRewriteRule ^(.*)/$ /$1 [R=301,L]

Page 85: Advanced symfony Techniques

GET /about/ HTTP/1.1Host: domain.com

HTTP/1.1 301 Moved PermanentlyLocation: http://domain.com/about

Page 86: Advanced symfony Techniques

Embedded Forms

Page 87: Advanced symfony Techniques

Person

One book has many authors,one author has many books.

Book

Authors

Page 88: Advanced symfony Techniques

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)

Page 89: Advanced symfony Techniques
Page 90: Advanced symfony Techniques

// embed related forms$this->embedRelation('authors');unset($this['authors_list']);

Page 91: Advanced symfony Techniques
Page 92: Advanced symfony Techniques
Page 93: Advanced symfony Techniques
Page 94: Advanced symfony Techniques
Page 95: Advanced symfony Techniques
Page 96: Advanced symfony Techniques
Page 97: Advanced symfony Techniques

// embed related forms dynamically!$this->embedDynamicRelation('authors');

Page 98: Advanced symfony Techniques

form.method_not_found

form.filter_values

Page 99: Advanced symfony Techniques

// called when a form is configuredpublic function embedDynamicRelation($name){ $rel = $table->getRelation($name); $this->rels[] = $rel;

$this->doEmbed($name, $obj->get($rel->getAlias()));}

Page 100: Advanced symfony Techniques

// called when a form is boundpublic function filterValues(sfEvent $event, $values){ foreach ($this->rels as $rel) { $name = $rel->getName(); $this->doEmbed($name, $values[$name]); }

$obj->addListener(new DeleteListener($form));}

Page 101: Advanced symfony Techniques

$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);

Page 102: Advanced symfony Techniques

// extract existing objects from embedded forms// and compare to the current object collectionpublic 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(); }}

Page 103: Advanced symfony Techniques

sfDoctrineDynamicFormRelationsPluginCommon sense embedded forms.

Page 104: Advanced symfony Techniques

Questions?

• Host aware routing

• Graceful POST authentication

• Extra security

• Javascript compression

• Apache tricks

• Embedded forms

Page 105: Advanced symfony Techniques

OpenSky is Hiring!http://engineering.shopopensky.com

Please contact me if you're interested.

Page 106: Advanced symfony Techniques

Thank you!