SlideShare uma empresa Scribd logo
1 de 116
Baixar para ler offline
How Kris Writes Symfony Apps
       @kriswallsmith • February 9, 2013
About Me
@kriswallsmith.net

•   Born, raised, & live in Portland

•   10+ years of experience

•   Lead Architect at OpenSky

•   Open source fanboy
brewcycleportland.com
assetic
Buzz
Spork
Go big or go home.
Getting Started
composer create-project 
    symfony/framework-standard-edition 
    opti-grab/ 2.2.x-dev
-   "doctrine/orm": "~2.2,>=2.2.3",
-   "doctrine/doctrine-bundle": "1.2.*",
+   "doctrine/mongodb-odm-bundle": "3.0.*",
+   "jms/serializer-bundle": "1.0.*",
./app/console generate:bundle 
    --namespace=OptiGrab/Bundle/MainBundle
assetic:
    debug:             %kernel.debug%
    use_controller:    false
    bundles:           [ MainBundle ]
    filters:
         cssrewrite:   ~
         uglifyjs2:    { compress: true, mangle: true }
         uglifycss:    ~
jms_di_extra:
    locations:
        bundles:
            - MainBundle
public function registerContainerConfiguration(LoaderInterface $loader)
{
    $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');

    // load local_*.yml or local.yml
    if (
         file_exists($file = __DIR__.'/config/local_'.$this->getEnvironment().'.yml')
         ||
         file_exists($file = __DIR__.'/config/local.yml')
    ) {
         $loader->load($file);
    }
}
MongoDB
Treat your model like a princess.
She gets her own wing
   of the palace…
doctrine_mongodb:
    auto_generate_hydrator_classes: %kernel.debug%
    auto_generate_proxy_classes:      %kernel.debug%
    connections: { default: ~ }
    document_managers:
        default:
            connection: default
            database:     optiGrab
            mappings:
                 model:
                     type:    annotation
                     dir:     %src_dir%/OptiGrab/Model
                     prefix: OptiGrabModel
                     alias: Model
// repo for src/OptiGrab/Model/Widget.php
$repo = $this->dm->getRepository('Model:User');
…doesn't do any work…
use OptiGrabBundleMainBundleCanonicalizer;

public function setUsername($username)
{
    $this->username = $username;

    $canonicalizer = Canonicalizer::instance();
    $this->usernameCanonical = $canonicalizer->canonicalize($username);
}
use OptiGrabBundleMainBundleCanonicalizer;

public function setUsername($username, Canonicalizer $canonicalizer)
{
    $this->username = $username;
    $this->usernameCanonical = $canonicalizer->canonicalize($username);
}
…and is unaware of the work
  being done around her.
public function setUsername($username)
{
    // a listener will update the
    // canonical username
    $this->username = $username;
}
No query builders
outside of repositories
class WidgetRepository extends DocumentRepository
{
    public function findByUser(User $user)
    {
        return $this->createQueryBuilder()
            ->field('userId')->equals($user->getId())
            ->getQuery()
            ->execute();
    }

    public function updateDenormalizedUsernames(User $user)
    {
        $this->createQueryBuilder()
            ->update()
            ->multiple()
            ->field('userId')->equals($user->getId())
            ->field('userName')->set($user->getUsername())
            ->getQuery()
            ->execute();
    }
}
Eager id creation
public function __construct()
{
    $this->id = (string) new MongoId();
}
public function __construct()
{
    $this->id = (string) new MongoId();
    $this->createdAt = new DateTime();
    $this->widgets = new ArrayCollection();
}
Remember your
clone constructor
$foo = new Foo();
$bar = clone $foo;
public function __clone()
{
    $this->id = (string) new MongoId();
    $this->createdAt = new DateTime();
    $this->widgets = new ArrayCollection(
        $this->widgets->toArray()
    );
}
public function __construct()
{
    $this->id = (string) new MongoId();
    $this->createdAt = new DateTime();
    $this->widgets = new ArrayCollection();
}

public function __clone()
{
    $this->id = (string) new MongoId();
    $this->createdAt = new DateTime();
    $this->widgets = new ArrayCollection(
        $this->widgets->toArray()
    );
}
Only flush from the controller
public function theAction(Widget $widget)
{
    $this->get('widget_twiddler')
         ->skeedaddle($widget);
    $this->flush();
}
Save space on field names
/** @ODMString(name="u") */
private $username;

/** @ODMString(name="uc") @ODMUniqueIndex */
private $usernameCanonical;
public function getUsername()
{
    return $this->username ?: $this->usernameCanonical;
}

public function setUsername($username)
{
    if ($username) {
        $this->usernameCanonical = strtolower($username);
        $this->username = $username === $this->usernameCanonical ? null : $username;
    } else {
        $this->usernameCanonical = null;
        $this->username = null;
    }
}
No proxy objects
/** @ODMReferenceOne(targetDocument="User") */
private $user;
public function getUser()
{
    if ($this->userId && !$this->user) {
        throw new UninitializedReferenceException('user');
    }

    return $this->user;
}
Mapping Layers
What is a mapping layer?
A mapping layer is thin
Thin controller, fat model…
Is Symfony an MVC framework?
Symfony is an HTTP framework
Application Land
  Controller
  HTTP Land
The controller maps from
HTTP-land to application-land.
What about the model?
public function registerAction()
{
    // ...
    $user->sendWelcomeEmail();
    // ...
}
public function registerAction()
{
    // ...
    $mailer->sendWelcomeEmail($user);
    // ...
}
Persistence Land
    Model
Application Land
The model maps from
application-land to persistence-land.
Persistence Land
     Model
Application Land
  Controller
  HTTP Land
Who lives in application land?
Thin controller, thin model…
      Fat service layer!
Application Events
Use lots of them
That happened.
/** @DIObserve("user.username_change") */
public function onUsernameChange(UserEvent $event)
{
    $user = $event->getUser();
    $dm   = $event->getDocumentManager();

    $dm->getRepository('Model:Widget')
       ->updateDenormalizedUsernames($user);
}
Unit of Work
public function onFlush(OnFlushEventArgs $event)
{
    $dm = $event->getDocumentManager();
    $uow = $dm->getUnitOfWork();

    foreach ($uow->getIdentityMap() as $class => $docs) {
        if (self::checkClass('OptiGrabModelUser', $class)) {
            foreach ($docs as $doc) {
                $this->processUserFlush($dm, $doc);
            }
        } elseif (self::checkClass('OptiGrabModelWidget', $class)) {
            foreach ($docs as $doc) {
                $this->processWidgetFlush($dm, $doc);
            }
        }
    }
}
private function processUserFlush(DocumentManager $dm, User $user)
{
    $uow     = $dm->getUnitOfWork();
    $meta    = $dm->getClassMetadata('Model:User');
    $changes = $uow->getDocumentChangeSet($user);

    if (isset($changes['id'][1])) {
        $this->dispatcher->dispatch(UserEvents::CREATE, new UserEvent($dm, $user));
    }

    if (isset($changes['usernameCanonical'][0]) && null !== $changes['usernameCanonical'][0]) {
        $this->dispatcher->dispatch(UserEvents::USERNAME_CHANGE, new UserEvent($dm, $user));
    }

    if ($followedUsers = $meta->getFieldValue($user, 'followedUsers')) {
        foreach ($followedUsers->getInsertDiff() as $otherUser) {
            $this->dispatcher->dispatch(
                UserEvents::FOLLOW_USER,
                new UserUserEvent($dm, $user, $otherUser)
            );
        }

        foreach ($followedUsers->getDeleteDiff() as $otherUser) {
            // ...
        }
    }
}
/** @DIObserve("user.create") */
public function onUserCreate(UserEvent $event)
{
    $user = $event->getUser();

    $activity = new Activity();
    $activity->setActor($user);
    $activity->setVerb('register');
    $activity->setCreatedAt($user->getCreatedAt());

    $this->dm->persist($activity);
}
/** @DIObserve("user.create") */
public function onUserCreate(UserEvent $event)
{
    $dm   = $event->getDocumentManager();
    $user = $event->getUser();

    $widget = new Widget();
    $widget->setUser($user);

    $dm->persist($widget);

    // manually notify the event
    $event->getDispatcher()->dispatch(
        WidgetEvents::CREATE,
        new WidgetEvent($dm, $widget)
    );
}
/** @DIObserve("user.follow_user") */
public function onFollowUser(UserUserEvent $event)
{
    $event->getUser()
          ->getStats()
          ->incrementFollowedUsers(1);
    $event->getOtherUser()
          ->getStats()
          ->incrementFollowers(1);
}
Two event classes per model
• @MainBundleUserEvents: encapsulates event name constants
  such as UserEvents::CREATE and
  UserEvents::CHANGE_USERNAME

• @MainBundleEventUserEvent: base event object, accepts
  $dm and $user arguments

• @MainBundleWidgetEvents…
• @MainBundleEventWidgetEvent…
$event = new UserEvent($dm, $user);
$dispatcher->dispatch(UserEvents::CREATE, $event);
Delegate work to clean, concise,
 single-purpose event listeners
Contextual Configuration
Save your future self a headache
# @MainBundle/Resources/config/widget.yml
services:
    widget_twiddler:
        class: OptiGrabBundleMainBundleWidgetTwiddler
        arguments:
            - @event_dispatcher
            - @?logger
/** @DIService("widget_twiddler") */
class Twiddler
{
    /** @DIInjectParams */
    public function __construct(
        EventDispatcherInterface $dispatcher,
        LoggerInterface $logger = null)
    {
        // ...
    }
}
services:
    # aliases for auto-wiring
    container: @service_container
    dm: @doctrine_mongodb.odm.document_manager
    doctrine: @doctrine_mongodb
    dispatcher: @event_dispatcher
    security: @security.context
JMSDiExtraBundle
require.js
<script src="{{ asset('js/lib/require.js') }}"></script>
<script>
require.config({
    baseUrl: "{{ asset('js') }}",
    paths: {
         "jquery": "//ajax.googleapis.com/.../jquery.min",
         "underscore": "lib/underscore",
         "backbone": "lib/backbone"
    },
    shim: {
         "jquery": { exports: "jQuery" },
         "underscore": { exports: "_" },
         "backbone": {
             deps: [ "jquery", "underscore" ],
             exports: "Backbone"
         }
    }
})
require([ "main" ])
</script>
// web/js/model/user.js
define(
    [ "underscore", "backbone" ],
    function(_, Backbone) {
        var tmpl = _.template("<%- first %> <%- last %>")
        return Backbone.Model.extend({
            name: function() {
                return tmpl({
                    first: this.get("first_name"),
                    last: this.get("last_name")
                })
            }
        })
    }
)
{% block head %}
<script>
require(
    [ "view/user", "model/user" ],
    function(UserView, User) {
         var view = new UserView({
             model: new User({{ user|serialize|raw }}),
             el: document.getElementById("user")
         })
    }
)
</script>
{% endblock %}
Dependencies


•   model: backbone, underscore

•   view: backbone, jquery

•   template: model, view
{% javascripts
    "js/lib/jquery.js" "js/lib/underscore.js"
    "js/lib/backbone.js" "js/model/user.js"
    "js/view/user.js"
    filter="?uglifyjs2" output="js/packed/user.js" %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}

<script>
var view = new UserView({
    model: new User({{ user|serialize|raw }}),
    el: document.getElementById("user")
})
</script>
Unused dependencies
 naturally slough off
JMSSerializerBundle
{% block head %}
<script>
require(
    [ "view/user", "model/user" ],
    function(UserView, User) {
         var view = new UserView({
             model: new User({{ user|serialize|raw }}),
             el: document.getElementById("user")
         })
    }
)
</script>
{% endblock %}
/** @ExclusionPolicy("ALL") */
class User
{
    private $id;

    /** @Expose */
    private $firstName;

    /** @Expose */
    private $lastName;
}
Miscellaneous
When to create a new bundle
Lots of classes pertaining to
        one feature
{% include 'MainBundle:Account/Widget:sidebar.html.twig' %}
{% include 'AccountBundle:Widget:sidebar.html.twig' %}
Access Control
The Symfony ACL is for
 arbitrary permissions
Encapsulate access logic in
  custom voter classes
/** @DIService(public=false) @DITag("security.voter") */
class WidgetVoter implements VoterInterface
{
    public function supportsAttribute($attribute)
    {
        return 'OWNER' === $attribute;
    }

    public function supportsClass($class)
    {
        return 'OptiGrabModelWidget' === $class
            || is_subclass_of($class, 'OptiGrabModelWidget');
    }

    public function vote(TokenInterface $token, $widget, array $attributes)
    {
        // ...
    }
}
public function vote(TokenInterface $token, $map, array $attributes)
{
    $result = VoterInterface::ACCESS_ABSTAIN;

    if (!$this->supportsClass(get_class($map))) {
        return $result;
    }

    foreach ($attributes as $attribute) {
        if (!$this->supportsAttribute($attribute)) {
            continue;
        }

        $result = VoterInterface::ACCESS_DENIED;
        if ($token->getUser() === $map->getUser()) {
            return VoterInterface::ACCESS_GRANTED;
        }
    }

    return $result;
}
/** @SecureParam(name="widget", permissions="OWNER") */
public function editAction(Widget $widget)
{
    // ...
}
{% if is_granted('OWNER', widget) %}
{# ... #}
{% endif %}
Only mock interfaces
interface FacebookInterface
{
    function getUser();
    function api();
}

/** @DIService("facebook") */
class Facebook extends BaseFacebook implements FacebookInterface
{
    // ...
}
$facebook = $this->getMock('OptiGrabBundleMainBundleFacebookFacebookInterface');
$facebook->expects($this->any())
    ->method('getUser')
    ->will($this->returnValue(123));
Questions?
@kriswallsmith.net



        joind.in/8024


      Thank You!

Mais conteúdo relacionado

Mais procurados

Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDAleix Vergés
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryRemy Sharp
 
An Introduction to Jquery
An Introduction to JqueryAn Introduction to Jquery
An Introduction to JqueryPhil Reither
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery ApplicationsRebecca Murphey
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code OrganizationRebecca Murphey
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
amsterdamjs - jQuery 1.5
amsterdamjs - jQuery 1.5amsterdamjs - jQuery 1.5
amsterdamjs - jQuery 1.5mennovanslooten
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuerysergioafp
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Eventsdmethvin
 
Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsRebecca Murphey
 
Jqeury ajax plugins
Jqeury ajax pluginsJqeury ajax plugins
Jqeury ajax pluginsInbal Geffen
 
Kick start with j query
Kick start with j queryKick start with j query
Kick start with j queryMd. Ziaul Haq
 

Mais procurados (20)

Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
jQuery: Events, Animation, Ajax
jQuery: Events, Animation, AjaxjQuery: Events, Animation, Ajax
jQuery: Events, Animation, Ajax
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQuery
 
An Introduction to Jquery
An Introduction to JqueryAn Introduction to Jquery
An Introduction to Jquery
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery Applications
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code Organization
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
amsterdamjs - jQuery 1.5
amsterdamjs - jQuery 1.5amsterdamjs - jQuery 1.5
amsterdamjs - jQuery 1.5
 
Special Events
Special EventsSpecial Events
Special Events
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuery
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Events
 
Beyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS AppsBeyond the DOM: Sane Structure for JS Apps
Beyond the DOM: Sane Structure for JS Apps
 
Jqeury ajax plugins
Jqeury ajax pluginsJqeury ajax plugins
Jqeury ajax plugins
 
Dojo Confessions
Dojo ConfessionsDojo Confessions
Dojo Confessions
 
Jquery Fundamentals
Jquery FundamentalsJquery Fundamentals
Jquery Fundamentals
 
Kick start with j query
Kick start with j queryKick start with j query
Kick start with j query
 

Semelhante a How Kris Writes Symfony Apps

Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
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
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionPhilip Norton
 
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
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Jakub Zalas
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperJonathan Wage
 
Et si on en finissait avec CRUD ?
Et si on en finissait avec CRUD ?Et si on en finissait avec CRUD ?
Et si on en finissait avec CRUD ?Julien Vinber
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Version Control with Puppet
Version Control with PuppetVersion Control with Puppet
Version Control with PuppetPuppet
 
PuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with PuppetPuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with PuppetWalter Heck
 

Semelhante a How Kris Writes Symfony Apps (20)

Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
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
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
BEAR DI
BEAR DIBEAR DI
BEAR DI
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency Injection
 
Symfony2 your way
Symfony2   your waySymfony2   your way
Symfony2 your way
 
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
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Doctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document MapperDoctrine MongoDB Object Document Mapper
Doctrine MongoDB Object Document Mapper
 
Et si on en finissait avec CRUD ?
Et si on en finissait avec CRUD ?Et si on en finissait avec CRUD ?
Et si on en finissait avec CRUD ?
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Version Control with Puppet
Version Control with PuppetVersion Control with Puppet
Version Control with Puppet
 
PuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with PuppetPuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with Puppet
 

Mais de Kris Wallsmith

Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Kris Wallsmith
 
Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)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
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
A Practical Introduction to Symfony2
A Practical Introduction to Symfony2A Practical Introduction to Symfony2
A Practical Introduction to Symfony2Kris Wallsmith
 

Mais de Kris Wallsmith (11)

The View From Inside
The View From InsideThe View From Inside
The View From Inside
 
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 (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)
 
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
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
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
 

Último

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
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
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
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
"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
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
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
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
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
 
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
 
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
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 

Último (20)

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)
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
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
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
"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
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
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
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
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!
 
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
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
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
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 

How Kris Writes Symfony Apps