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

Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 

Recently uploaded (20)

Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 

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.