SlideShare une entreprise Scribd logo
1  sur  41
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
Zend Lucene
minify ( http://code.google.com/p/minify/ )


... 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
Demo #1

In-context editing

Button slots

Media repository

Cropping

Version History

... All “free” when you build custom slots
8
... 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


... And layouts, and (page) templates, and plain old Symfony actions
Templates: adding slots and areas

     <?php a_area('link', array( 
   'area_add_content_label' => 'Add Program', 
    'allowed_types' => array(
     'aButton',     
    ),
  'type_options' => array(
     'aButton' => array(
       'itemTemplate' => 'homeButton', 
       'width' => 144, 
       // 'flexHeight' => true, 
       'height' => 124, 
       // 'resizeType' => 'c', 
       'constraints' => array(
         'minimum-width' => 144, 'minimum-height' => 124, 
         'aspect-width' => 144, 'aspect-height' => 124),  
       'title' => true, 
       'description' => false)))) ?>
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');
  }
}
aFeedForm validators

    $this->setValidators(array('url' => new sfValidatorAnd(array(
  // @foo => correct twitter RSS feed URL
  new sfValidatorCallback(
    array('callback' => array($this, 'validateTwitterHandle'))), 
  // www.foo.bar => http://www.foo.bar
  new sfValidatorCallback(
    array('callback' => array($this, 'validateLazyUrl'))), 
  // Must be a valid URL to go past this stage
  new sfValidatorUrl(
    array('required' => true, 'max_length' => 1024)), 
  // Find feeds via meta tags in plain old pages
  new sfValidatorCallback(
    array('callback' => array($this, 'validateFeed')))))));
validateFeed: find feeds in plain pages

    public function validateFeed($validator, $value)
  {
    $content = @file_get_contents($value);
    if ($content)
    {
      $html = new DOMDocument();
      @$html->loadHTML($content);
      $xpath = new DOMXPath($html);
      $arts = $xpath->query('//link[@rel="alternate" and @type="application/rss+xml"]');
      if (isset($arts->length) && $arts->length)
      {
        return $arts->item(0)->getAttribute('href');
      }
    }
    return $value;
  }
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
Virtual pages

• Any page object with a slug not starting with /
• Efficiently stores slots & areas that will be needed together
• ... Which is how our blog plugin works
• Created on demand when you save the first slot
• ... Or in advance, paired with another object (blog post)
• Search treats these as routes: @blog_show?id=5, blog/show?id=5
• Search ignores this: not-searchable-57
• a_area(‘blog-body’, array(‘slug’ => “@blog_show?id=$id”))
Demo #2

Various actions of the event engine page

Category filtering (with nice URLs)

Permalink pages (with nice URLs)

Some nice features of the blog (and event) plugin

Virtual pages for blog and event content

The feed slot does its magic
27
Too friendly?

•   “If it’s friendly it must be for small sites”
•   More users = more training?
•   Can you afford to train 100 people?
•   Less training required = more scalable
Demo #3: features for big sites

• Access controls
• Reorganizing the page tree
30
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
http://joind.in/view/talk/2744
        apostrophenow.com

Contenu connexe

Tendances

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right wayAnthony Hortin
 
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
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Fabien Potencier
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressJeroen van Dijk
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressJeroen van Dijk
 
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
 
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learned
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learnedMoving a high traffic ZF1 Enterprise Application to SF2 - Lessons learned
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learnedBaldur Rensch
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Developing For The WordPress Customizer
Developing For The WordPress CustomizerDeveloping For The WordPress Customizer
Developing For The WordPress CustomizerAnthony Hortin
 

Tendances (20)

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right way
 
New in php 7
New in php 7New in php 7
New in php 7
 
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
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/PressThe Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
 
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
 
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learned
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learnedMoving a high traffic ZF1 Enterprise Application to SF2 - Lessons learned
Moving a high traffic ZF1 Enterprise Application to SF2 - Lessons learned
 
Data Validation models
Data Validation modelsData Validation models
Data Validation models
 
Twig tips and tricks
Twig tips and tricksTwig tips and tricks
Twig tips and tricks
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Developing For The WordPress Customizer
Developing For The WordPress CustomizerDeveloping For The WordPress Customizer
Developing For The WordPress Customizer
 
PHP MVC
PHP MVCPHP MVC
PHP MVC
 

Similaire à Apostrophe (improved Paris edition)

関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
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.8Michelangelo van Dam
 
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
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
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
 
Web internship Yii Framework
Web internship  Yii FrameworkWeb internship  Yii Framework
Web internship Yii FrameworkNoveo
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3Mizanur Rahaman Mizan
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPDan Jesus
 
Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009hugowetterberg
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress WebsitesKyle Cearley
 

Similaire à Apostrophe (improved Paris edition) (20)

関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
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
 
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
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
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)
 
Web internship Yii Framework
Web internship  Yii FrameworkWeb internship  Yii Framework
Web internship Yii Framework
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3WordPress Theme Design and Development Workshop - Day 3
WordPress Theme Design and Development Workshop - Day 3
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
 
Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009Services Drupalcamp Stockholm 2009
Services Drupalcamp Stockholm 2009
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress Websites
 

Dernier

Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 

Dernier (20)

Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 

Apostrophe (improved Paris edition)

  • 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 Zend Lucene minify ( http://code.google.com/p/minify/ ) ... 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. Demo #1 In-context editing Button slots Media repository Cropping Version History ... All “free” when you build custom slots
  • 8. 8
  • 9. ... 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 ... And layouts, and (page) templates, and plain old Symfony actions
  • 10. Templates: adding slots and areas  <?php a_area('link', array(     'area_add_content_label' => 'Add Program',      'allowed_types' => array(      'aButton',          ),   'type_options' => array(      'aButton' => array(        'itemTemplate' => 'homeButton',         'width' => 144,         // 'flexHeight' => true,         'height' => 124,         // 'resizeType' => 'c',         'constraints' => array( 'minimum-width' => 144, 'minimum-height' => 124,  'aspect-width' => 144, 'aspect-height' => 124),          'title' => true,         'description' => false)))) ?>
  • 11. Feed Slot: schema.yml aFeedSlot: inheritance: extends: aSlot type: column_aggregation keyField: type keyValue: 'aFeed'
  • 12. 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()); } } ... }
  • 13. 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, ...); ... } }
  • 14. 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 ?>
  • 15. 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>
  • 16. 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(); } ...
  • 17. 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'); } }
  • 18. aFeedForm validators $this->setValidators(array('url' => new sfValidatorAnd(array(   // @foo => correct twitter RSS feed URL new sfValidatorCallback( array('callback' => array($this, 'validateTwitterHandle'))),    // www.foo.bar => http://www.foo.bar   new sfValidatorCallback( array('callback' => array($this, 'validateLazyUrl'))),    // Must be a valid URL to go past this stage   new sfValidatorUrl( array('required' => true, 'max_length' => 1024)),    // Find feeds via meta tags in plain old pages   new sfValidatorCallback( array('callback' => array($this, 'validateFeed')))))));
  • 19. validateFeed: find feeds in plain pages public function validateFeed($validator, $value)   {     $content = @file_get_contents($value);     if ($content)     {       $html = new DOMDocument();       @$html->loadHTML($content);       $xpath = new DOMXPath($html);       $arts = $xpath->query('//link[@rel="alternate" and @type="application/rss+xml"]');       if (isset($arts->length) && $arts->length)       {         return $arts->item(0)->getAttribute('href');       }     }     return $value;   }
  • 20. 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
  • 21. 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
  • 22. 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')); } }
  • 23. 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-]+$ }
  • 24. 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
  • 25. Virtual pages • Any page object with a slug not starting with / • Efficiently stores slots & areas that will be needed together • ... Which is how our blog plugin works • Created on demand when you save the first slot • ... Or in advance, paired with another object (blog post) • Search treats these as routes: @blog_show?id=5, blog/show?id=5 • Search ignores this: not-searchable-57 • a_area(‘blog-body’, array(‘slug’ => “@blog_show?id=$id”))
  • 26. Demo #2 Various actions of the event engine page Category filtering (with nice URLs) Permalink pages (with nice URLs) Some nice features of the blog (and event) plugin Virtual pages for blog and event content The feed slot does its magic
  • 27. 27
  • 28. Too friendly? • “If it’s friendly it must be for small sites” • More users = more training? • Can you afford to train 100 people? • Less training required = more scalable
  • 29. Demo #3: features for big sites • Access controls • Reorganizing the page tree
  • 30. 30
  • 31. 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...'))); ?>
  • 39. Conclusions 1.5 is awesome now 2.0 will be awesome later You are awesome Let's be awesome together
  • 40. apostrophenow.com apostrophenow.com
  • 41. http://joind.in/view/talk/2744 apostrophenow.com

Notes de l'éditeur

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n