SlideShare a Scribd company logo
1 of 106
Download to read offline
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!

More Related Content

What's hot

Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of LithiumNate Abele
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupKacper Gunia
 

What's hot (20)

Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
New in php 7
New in php 7New in php 7
New in php 7
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Nubilus Perl
Nubilus PerlNubilus Perl
Nubilus Perl
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 

Viewers also liked

Upgrading to php 5.6
Upgrading to php 5.6Upgrading to php 5.6
Upgrading to php 5.6Luka Skupnjak
 
Trick or Tip - Symfony Edition
Trick or Tip - Symfony EditionTrick or Tip - Symfony Edition
Trick or Tip - Symfony EditionDionyshs Tsoumas
 
Symfony2: Get your project started
Symfony2: Get your project startedSymfony2: Get your project started
Symfony2: Get your project startedRyan Weaver
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackIgnacio Martín
 
TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma Badoo Development
 
TechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoTechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoBadoo Development
 
TechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooTechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooBadoo Development
 
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruTechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruBadoo Development
 

Viewers also liked (10)

Upgrading to php 5.6
Upgrading to php 5.6Upgrading to php 5.6
Upgrading to php 5.6
 
Trick or Tip - Symfony Edition
Trick or Tip - Symfony EditionTrick or Tip - Symfony Edition
Trick or Tip - Symfony Edition
 
Deployment talk dpc 13
Deployment talk dpc 13Deployment talk dpc 13
Deployment talk dpc 13
 
Symfony2: Get your project started
Symfony2: Get your project startedSymfony2: Get your project started
Symfony2: Get your project started
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and Webpack
 
TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma TechLeads meetup: Евгений Потапов, ITSumma
TechLeads meetup: Евгений Потапов, ITSumma
 
TechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, ErlyvideoTechLeads meetup: Макс Лапшин, Erlyvideo
TechLeads meetup: Макс Лапшин, Erlyvideo
 
TechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, BadooTechLeads meetup: Алексей Рыбак, Badoo
TechLeads meetup: Алексей Рыбак, Badoo
 
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ruTechLeads meetup: Андрей Шелёхин, Tinkoff.ru
TechLeads meetup: Андрей Шелёхин, Tinkoff.ru
 

Similar to Advanced symfony Techniques

関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHPHari K T
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationBrent Shaffer
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
Resource Routing in ExpressionEngine
Resource Routing in ExpressionEngineResource Routing in ExpressionEngine
Resource Routing in ExpressionEngineMichaelRog
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkJeremy Kendall
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3Nate Abele
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy Kendall
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
Filesystem abstractions and msg queue sergeev - symfony camp 2018
Filesystem abstractions and msg queue   sergeev - symfony camp 2018Filesystem abstractions and msg queue   sergeev - symfony camp 2018
Filesystem abstractions and msg queue sergeev - symfony camp 2018Юлия Коваленко
 
What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012D
 
第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 DatasourceKaz Watanabe
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?Alexandru Badiu
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Jakub Zalas
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overviewjsmith92
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model Perforce
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)tompunk
 
Apostrophe
ApostropheApostrophe
Apostrophetompunk
 

Similar to Advanced symfony Techniques (20)

関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Aura Project for PHP
Aura Project for PHPAura Project for PHP
Aura Project for PHP
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes Presentation
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Resource Routing in ExpressionEngine
Resource Routing in ExpressionEngineResource Routing in ExpressionEngine
Resource Routing in ExpressionEngine
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Filesystem abstractions and msg queue sergeev - symfony camp 2018
Filesystem abstractions and msg queue   sergeev - symfony camp 2018Filesystem abstractions and msg queue   sergeev - symfony camp 2018
Filesystem abstractions and msg queue sergeev - symfony camp 2018
 
What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012
 
第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource
 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
 
Apostrophe
ApostropheApostrophe
Apostrophe
 

More from Kris Wallsmith

How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayKris Wallsmith
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Kris Wallsmith
 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Kris Wallsmith
 
A Practical Introduction to Symfony2
A Practical Introduction to Symfony2A Practical Introduction to Symfony2
A Practical Introduction to Symfony2Kris Wallsmith
 

More from Kris Wallsmith (14)

Matters of State
Matters of StateMatters of State
Matters of State
 
The View From Inside
The View From InsideThe View From Inside
The View From Inside
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
Drupal, meet Assetic
Drupal, meet AsseticDrupal, meet Assetic
Drupal, meet Assetic
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Assetic (Zendcon)
Assetic (Zendcon)Assetic (Zendcon)
Assetic (Zendcon)
 
Assetic (OSCON)
Assetic (OSCON)Assetic (OSCON)
Assetic (OSCON)
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)
 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3
 
A Practical Introduction to Symfony2
A Practical Introduction to Symfony2A Practical Introduction to Symfony2
A Practical Introduction to Symfony2
 
Symfony 2
Symfony 2Symfony 2
Symfony 2
 
Symfony in the Cloud
Symfony in the CloudSymfony in the Cloud
Symfony in the Cloud
 

Recently uploaded

Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 

Recently uploaded (20)

Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 

Advanced symfony Techniques

  • 2. @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…
  • 3. DbFinderPlugin • sfPropelActAsPolymorphicBehaviorPlugin • sfControlPanelPlugin • sfSimpleBlogPlugin • sfDoctrineDynamicFormRelationsPlugin • sfSimpleCMSPlugin • sfDoctrineMasterSlavePlugin • sfSimpleForumPlugin • sfFeed2Plugin • sfSpyPlugin • sfFormYamlEnhancementsPlugin • sfSslRequirementPlugin • sfGoogleAnalyticsPlugin • sfStatsPlugin • sfGoogleWebsiteOptimizerPlugin • sfTaskExtraPlugin • sfModerationPlugin • sfWebBrowserPlugin • sfPagerNavigationPlugin
  • 4. Please see me if you want to help with or take over a plugin's maintenance. Lots to choose from!
  • 5. #phpmatsuri October 2-3, 2010 Tokyo
  • 6. #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!
  • 7.
  • 13. homepage: url: / param: { module: main, action: indexOrDash }
  • 14. homepage: url: / param: { module: main, action: indexOrDash } if (preg_match('/.../', $r->getHost(), $m))
  • 15. class sfRoute • ->matchesUrl(...) Does the supplied URL match this route? GET / HTTP/1.0 Host: foobar.domain.com
  • 16. 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?
  • 17. 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.
  • 18. ->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
  • 19. ->matchesParameters(...) • $params An associative array of parameter names and values • $context An array of contextual information, including the current host • Returns true or false
  • 20. ->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
  • 21. Process the host string with a second, internal route
  • 22. public function __construct(...) { list($host, $pattern) = explode('/', $pattern, 2); $hostRoute = $this->createHostRoute($host, ...); parent::__construct(...); }
  • 23. public function matchesUrl($url, $c) { // check parent::matchesUrl() first $hp = $hostRoute->matchesUrl('/'.$c['host'], $c); // include host parameters in return }
  • 24. public function matchesParameters($p, $c) { $hp = $this->extractHostParams($p); return parent::matchesParameters($p, $c) && $hostRoute->matchesParameters($hp, $c); }
  • 25. 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; }
  • 26. homepage: url: / param: { module: main, action: indexOrDash }
  • 27. 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 }
  • 28. homepage: url: %APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: index } dashboard: url: :username.%APP_HOST%/ class: sfHostAwareRoute param: { module: main, action: dashboard }
  • 30. class sfHostAwareRoutingConfigHandler extends sfRoutingConfigHandler { protected function parse($configFiles) { return array_map( array($this, 'filterRoute'), parent::parse($configFiles) ); } // ... }
  • 31. FTW! Free protected function filterRoute($route) { list($class, $args) = $route; $args[0] = $this->replaceConstants($args[0]); return array($class, $args); }
  • 32. # config_handlers.yml config/routing.yml: class: sfHostAwareRoutingConfigHandler file: %SF_LIB_DIR%/sfHostAwareRout...
  • 33. sfHostAwareRoutingPlugin Add subdomains to your routing rules.
  • 36.
  • 37.
  • 39.
  • 40. W here's my blog pos t!? ! AIL F
  • 42. 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(); } }
  • 43. # filters.yml security: class: GracefulSecurityFilter
  • 44. Replay the stashed request after login
  • 45. // 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']); } }
  • 48.
  • 49.
  • 50. # security.yml acceptInvitation: is_secure: true extra_credentials: account: { lifetime: 300 }
  • 51. Events to the rescue!
  • 53. // connect to the event $ed->connect('controller.change_action', $cb)
  • 55. // check current user $u->getAttribute('extra_credentials', array())
  • 56. // remove any expired credentials $now = time(); foreach ($creds as $name => $attr) { if ($now > $attr['expires_at']) { unset($creds[$name]); } }
  • 57. // stash credentials and referer $u->setAttribute('challenge_credentials', ...) $u->setAttribute('challenge_referer', ...)
  • 58. // forward to challenge form $controller->forward('security', 'challenge') throw new sfStopException();
  • 59. // add the granted credentials $now = time(); foreach ($new as $name => $attr) { $creds[$name] = array( 'expires_at' => $now + $attr['lifetime'], ); } $u->setAttribute('extra_credentials', $creds);
  • 60. // send them on their way $this->redirect($referer);
  • 61. sfExtraSecurityPlugin Re-prompt your users for authentication.
  • 64. class jsActions extends sfActions { public function executeWidget(sfWebRequest $req) { $this->lightbox = $req->hasParameter('lb'); $this->debug = $req->hasParameter('debug'); } }
  • 65. <?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...
  • 67. # module.yml all: view_class: Javascript JavascriptView
  • 68. class JavascriptView extends sfPHPView { public function render() { return $this->compress(parent::render()); } protected function compress() { // ... } }
  • 69. $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);
  • 71. # cache.yml widget: enabled: true with_layout: true
  • 73. A Few Apache Tricks
  • 76. <Directory /path/to/web> Include /path/to/.htaccess </Directory>
  • 78. Missing Asset s #FAIL :(
  • 79. AliasMatch /sf/(.*) /path/to/symfony/data/web/sf/$1 AliasMatch /sfDoctrinePlugin/(.*) /path/to/sfDoctrinePlugin/web/$1 NameVirtualHost *:80 <VirtualHost _default_:80> # ...
  • 80. Assets Fo u nd FTW!
  • 82.
  • 85. GET /about/ HTTP/1.1 Host: domain.com HTTP/1.1 301 Moved Permanently Location: http://domain.com/about
  • 87. Book One book has many authors, Authors one author has many books. Person
  • 88. 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)
  • 89.
  • 90. // embed related forms $this->embedRelation('authors'); unset($this['authors_list']);
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97. // embed related forms dynamically! $this->embedDynamicRelation('authors');
  • 99. // called when a form is configured public function embedDynamicRelation($name) { $rel = $table->getRelation($name); $this->rels[] = $rel; $this->doEmbed($name, $obj->get($rel->getAlias())); }
  • 100. // 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)); }
  • 101. $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);
  • 102. // 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(); } }
  • 103. sfDoctrineDynamicFormRelationsPlugin Common sense embedded forms.
  • 104. Questions? • Host aware routing • Graceful POST authentication • Extra security • Javascript compression • Apache tricks • Embedded forms
  • 105. OpenSky is Hiring! http://engineering.shopopensky.com Please contact me if you're interested.