SlideShare a Scribd company logo
1 of 29
Download to read offline
apostrophenow.com / punkave.com
A Symfony-powered CMS
   your clients will love

     Thomas Boutell
What is Apostrophe?

Content Management System 

Content Management Framework
On the shoulders of giants...

PHP

Symfony 1.4
Doctrine
MySQL 

... and ideas from sfSimpleCMSPlugin
Goals of Apostrophe

Easy for clients to update without specialized training

Hard for clients to screw up by accident!

Extensible by any Symfony developer
Making it easy

"When you log in, it just gets awesomer"

Do things in context

When you can't do things in context, keep it simple

Don't require a degree in Drupal-ogy!

Check it out: demo.apostrophenow.com
... OK, but how do you extend it?

Relax! It's Still Symfony (RISS)

Apostrophe embraces Symfony idioms

Slot = Doctrine inheritance +       Engine = Symfony module +
          Edit view component +                    aRoute & aDoctrineRoute +
          Normal view component +                  Apostrophe page as a "host"
          Edit action +
          Edit form
Feed Slot: schema.yml

aFeedSlot:
  inheritance:
    extends: aSlot
    type: column_aggregation
    keyField: type
    keyValue: 'aFeed'
Feed Slot: edit view component

class BaseaFeedSlotComponents extends aSlotComponents
{
  public function executeEditView()
  {
    $this->setup();
    // If this is the first validation pass make the form
    if (!isset($this->form))
    {
      $this->form = new aFeedForm($this->id, $this->slot-
>getArrayValue());
    }
  }
  ...
}
Feed Slot: normal view component

...
public function executeNormalView()
 {
    $this->setup();
    $this->values = $this->slot->getArrayValue();
     if (!empty($this->values['url']))
     {
       $this->feed = aFeed::fetchCachedFeed(
         $this->url, ...);
       ...
     }
 }
Feed Slot: edit view partial

<?php use_helper('a') ?>
<ul class="a-slot-info a-feed-info">
  <li><?php echo a_
('Paste an RSS feed URL, a Twitter @name (with the @),
' .
'or the URL of a page that offers a feed. Most blogs do.'
) ?></li>
</ul>
<?php echo $form ?>
Feed Slot: normal view partial

<?php use_helper('a') ?>
<?php if ($editable): ?>
  <?php // Display the edit button ?>
  <?php include_partial('a/
simpleEditWithVariants', ... ) ?>
<?php endif ?>
<ul class="a-feed">
  <?php foreach ($feed->getItems() as $feedItem): ?>
    <?php include_partial('aFeedSlot/'.$options
['itemTemplate'],
      array('feedItem' => $feedItem, ... )) ?>
  <?php endforeach ?>
</ul>
Feed Slot: edit action
class aFeedSlotActions extends aSlotActions
{
  public function executeEdit(sfRequest $request)
  {
    $this->editSetup();
    $value = $this->getRequestParameter('slot-form-' . $this->id);
    $this->form = new aFeedForm($this->id, array());
    $this->form->bind($value);
    if ($this->form->isValid())
    {
      // Serialize usually better than extra db columns
      $this->slot->setArrayValue($this->form->getValues());
      return $this->editSave();
    } else
    {
      // Another validation pass
      return $this->editRetry();
    }
  ...
Feed Slot: aFeedForm
class aFeedForm extends BaseForm
{
  public function __construct($id = 1, $defaults = array())
  {
    $this->id = $id;
    parent::__construct();
    $this->setDefaults($defaults);
  }
  public function configure()
  {
    $this->setWidget('url', new sfWidgetFormInputText(
      array('label' => 'RSS Feed URL'))));
    // Validators for: Twitter handle, lazy URLs,
    // valid URLs, regular pages with feed URLs in meta tags
    $this->widgetSchema->setNameFormat('slot-form-' . $this-
>id . '[%s]');
    $this->widgetSchema->setFormFormatterName('aAdmin');
  }
}
apostrophe:generate-slot-type FTW!

./symfony apostrophe:generate-slot-type 
        --plugin=myPlugin 
        --type=monster

Generates:

schema.yml
Actions and components
monsterForm class

... Everything for a basic form-driven slot
Engines: multiple-page experiences

A Symfony module...

"Grafted" into the page tree

Multiple instances allowed

Easy to distinguish with categorized content

Examples: Bob's blog, Jane's blog, public photo gallery
Media engine: actions class (simplified)

class BaseaMediaActions extends aEngineActions
{
  public function executeIndex(sfWebRequest $request)
  {
    $this->items = Doctrine::getTable('aMediaItem')-
>findAll();
  }
    public function executeShow(sfWebRequest $request)
    {
      $this->item = Doctrine::getTable('aMediaItem')
        ->findOneBySlug($request->getParameter('slug'));
    }
}
Media engine: routing (yml style)

a_media_index:
  url: /
  class: aRoute
  param: { module: aMedia, action: index }

a_media_show:
  url: /view/:slug
  class: aRoute
  param: { module: aMedia, action: show }
  requirements: { slug: ^[w-]+$ }
Media engine: routing examples

1. /admin/media -> 
    Engine page /admin/media
    Matches a_media_index route (special case for /)

2. /admin/media/view/iguana -> 
    Engine page /admin/media 
    Matches a_media_show route, slug is iguana

3. /iguanapix/view/iguana ->
    Engine page /iguanapix
    Matches a_media_show route, slug is iguana
Bonus: safe, efficient JS calls + minifier
layout.php:
<head>
<?php a_use_javascripts() ?>
<?php a_use_stylesheets() ?>
</head>
<body>
... At the very END of the body:
<?php a_include_js_calls() ?>
</body>
_list_footer.php:
<?php a_js_call('apostrophe.enableUserAdmin(?)',
    array('choose-one-label' => a_('Choose One...'))); ?>
Apostrophe 2.0
Apostrophe 2.0
Apostrophe 2.0
Apostrophe 2.0
Apostrophe 2.0
Apostrophe 2.0
Apostrophe 2.0
Conclusions

1.5 is awesome now

2.0 will be awesome later

You are awesome

Let's be awesome together
apostrophenow.com
     apostrophenow.com

More Related Content

What's hot

Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP Extension
Adam Trachtenberg
 
Laying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme developmentLaying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme development
Tammy Hart
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 
PHP an intro -1
PHP an intro -1PHP an intro -1
PHP an intro -1
Kanchilug
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
Dan Jesus
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang
 

What's hot (19)

Current state-of-php
Current state-of-phpCurrent state-of-php
Current state-of-php
 
Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3
 
Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP Extension
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes Presentation
 
[PL] Jak nie zostać "programistą" PHP?
[PL] Jak nie zostać "programistą" PHP?[PL] Jak nie zostać "programistą" PHP?
[PL] Jak nie zostać "programistą" PHP?
 
Laying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme developmentLaying the proper foundation for plugin and theme development
Laying the proper foundation for plugin and theme development
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
PHP an intro -1
PHP an intro -1PHP an intro -1
PHP an intro -1
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Micropage in microtime using microframework
Micropage in microtime using microframeworkMicropage in microtime using microframework
Micropage in microtime using microframework
 
Keeping It Simple
Keeping It SimpleKeeping It Simple
Keeping It Simple
 
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
Let's write secure Drupal code! - DrupalCamp Oslo, 2018Let's write secure Drupal code! - DrupalCamp Oslo, 2018
Let's write secure Drupal code! - DrupalCamp Oslo, 2018
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Add loop shortcode
Add loop shortcodeAdd loop shortcode
Add loop shortcode
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 

Similar to Apostrophe

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 
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
D
 

Similar to Apostrophe (20)

関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
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
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Fatc
FatcFatc
Fatc
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Getting to The Loop - London Wordpress Meetup July 28th
Getting to The Loop - London Wordpress Meetup  July 28thGetting to The Loop - London Wordpress Meetup  July 28th
Getting to The Loop - London Wordpress Meetup July 28th
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC Framework
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
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
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 

Recently uploaded

TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 
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
Victor Rentea
 
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
Safe Software
 

Recently uploaded (20)

Simplifying Mobile A11y Presentation.pptx
Simplifying Mobile A11y Presentation.pptxSimplifying Mobile A11y Presentation.pptx
Simplifying Mobile A11y Presentation.pptx
 
The Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightThe Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and Insight
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
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
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
 
Design Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxDesign Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptx
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational Performance
 
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
 
JavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate GuideJavaScript Usage Statistics 2024 - The Ultimate Guide
JavaScript Usage Statistics 2024 - The Ultimate Guide
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation Computing
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 
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
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 
Overview of Hyperledger Foundation
Overview of Hyperledger FoundationOverview of Hyperledger Foundation
Overview of Hyperledger Foundation
 
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
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 

Apostrophe

  • 2. A Symfony-powered CMS your clients will love Thomas Boutell
  • 3. What is Apostrophe? Content Management System  Content Management Framework
  • 4. On the shoulders of giants... PHP Symfony 1.4 Doctrine MySQL  ... and ideas from sfSimpleCMSPlugin
  • 5. Goals of Apostrophe Easy for clients to update without specialized training Hard for clients to screw up by accident! Extensible by any Symfony developer
  • 6. Making it easy "When you log in, it just gets awesomer" Do things in context When you can't do things in context, keep it simple Don't require a degree in Drupal-ogy! Check it out: demo.apostrophenow.com
  • 7. ... OK, but how do you extend it? Relax! It's Still Symfony (RISS) Apostrophe embraces Symfony idioms Slot = Doctrine inheritance + Engine = Symfony module +           Edit view component +                aRoute & aDoctrineRoute +           Normal view component +                Apostrophe page as a "host"           Edit action +           Edit form
  • 8. Feed Slot: schema.yml aFeedSlot:   inheritance:     extends: aSlot     type: column_aggregation     keyField: type     keyValue: 'aFeed'
  • 9. Feed Slot: edit view component class BaseaFeedSlotComponents extends aSlotComponents { public function executeEditView() { $this->setup(); // If this is the first validation pass make the form if (!isset($this->form)) { $this->form = new aFeedForm($this->id, $this->slot- >getArrayValue()); } } ... }
  • 10. Feed Slot: normal view component ... public function executeNormalView() { $this->setup(); $this->values = $this->slot->getArrayValue(); if (!empty($this->values['url'])) { $this->feed = aFeed::fetchCachedFeed( $this->url, ...); ... } }
  • 11. Feed Slot: edit view partial <?php use_helper('a') ?> <ul class="a-slot-info a-feed-info"> <li><?php echo a_ ('Paste an RSS feed URL, a Twitter @name (with the @), ' . 'or the URL of a page that offers a feed. Most blogs do.' ) ?></li> </ul> <?php echo $form ?>
  • 12. Feed Slot: normal view partial <?php use_helper('a') ?> <?php if ($editable): ?> <?php // Display the edit button ?> <?php include_partial('a/ simpleEditWithVariants', ... ) ?> <?php endif ?> <ul class="a-feed"> <?php foreach ($feed->getItems() as $feedItem): ?> <?php include_partial('aFeedSlot/'.$options ['itemTemplate'], array('feedItem' => $feedItem, ... )) ?> <?php endforeach ?> </ul>
  • 13. Feed Slot: edit action class aFeedSlotActions extends aSlotActions { public function executeEdit(sfRequest $request) { $this->editSetup(); $value = $this->getRequestParameter('slot-form-' . $this->id); $this->form = new aFeedForm($this->id, array()); $this->form->bind($value); if ($this->form->isValid()) { // Serialize usually better than extra db columns $this->slot->setArrayValue($this->form->getValues()); return $this->editSave(); } else { // Another validation pass return $this->editRetry(); } ...
  • 14. Feed Slot: aFeedForm class aFeedForm extends BaseForm { public function __construct($id = 1, $defaults = array()) { $this->id = $id; parent::__construct(); $this->setDefaults($defaults); } public function configure() { $this->setWidget('url', new sfWidgetFormInputText( array('label' => 'RSS Feed URL')))); // Validators for: Twitter handle, lazy URLs, // valid URLs, regular pages with feed URLs in meta tags $this->widgetSchema->setNameFormat('slot-form-' . $this- >id . '[%s]'); $this->widgetSchema->setFormFormatterName('aAdmin'); } }
  • 15. apostrophe:generate-slot-type FTW! ./symfony apostrophe:generate-slot-type          --plugin=myPlugin          --type=monster Generates: schema.yml Actions and components monsterForm class ... Everything for a basic form-driven slot
  • 16. Engines: multiple-page experiences A Symfony module... "Grafted" into the page tree Multiple instances allowed Easy to distinguish with categorized content Examples: Bob's blog, Jane's blog, public photo gallery
  • 17. Media engine: actions class (simplified) class BaseaMediaActions extends aEngineActions { public function executeIndex(sfWebRequest $request) { $this->items = Doctrine::getTable('aMediaItem')- >findAll(); } public function executeShow(sfWebRequest $request) { $this->item = Doctrine::getTable('aMediaItem') ->findOneBySlug($request->getParameter('slug')); } }
  • 18. Media engine: routing (yml style) a_media_index: url: / class: aRoute param: { module: aMedia, action: index } a_media_show: url: /view/:slug class: aRoute param: { module: aMedia, action: show } requirements: { slug: ^[w-]+$ }
  • 19. Media engine: routing examples 1. /admin/media ->      Engine page /admin/media     Matches a_media_index route (special case for /) 2. /admin/media/view/iguana ->      Engine page /admin/media      Matches a_media_show route, slug is iguana 3. /iguanapix/view/iguana ->     Engine page /iguanapix     Matches a_media_show route, slug is iguana
  • 20. Bonus: safe, efficient JS calls + minifier layout.php: <head> <?php a_use_javascripts() ?> <?php a_use_stylesheets() ?> </head> <body> ... At the very END of the body: <?php a_include_js_calls() ?> </body> _list_footer.php: <?php a_js_call('apostrophe.enableUserAdmin(?)', array('choose-one-label' => a_('Choose One...'))); ?>
  • 28. Conclusions 1.5 is awesome now 2.0 will be awesome later You are awesome Let's be awesome together
  • 29. apostrophenow.com apostrophenow.com