Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Symfony Best Practices and beyond

Symfony Best Practices and beyond

At PHP PrameworksDay 2014

Oleg Zinchenko

November 15, 2014
Tweet

More Decks by Oleg Zinchenko

Other Decks in Programming

Transcript

  1. Disclaimer THE SOFTWARE SLIDES IS PROVIDED "AS IS" WITHOUT WARRANTY

    OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  2. Create only one bundle called AppBundle uberCMS/ ├─ app/ │

    ├─ console │ ├─ cache/ │ ├─ config/ │ └─ logs/ │ └─ Resources/ ├─ src/ │ └─ AppBundle/ ├─ vendor/ └─ web/ ├─ app.php └─ app_dev.php
  3. Create only one bundle called AppBundle What about API Bundle?

    What about Core Bundle? What about DDD? Do not use Sf3 dir structure... yet Imagine several kernels
  4. Infrastructure/App Related Configuration # app/config/config.yml imports: - resource: parameters.yml -

    resource: framework.yml - resource: doctrine.yml - resource: doctrine_extension.yml - resource: html_purifier.yml - resource: facebook.yml - resource: mailer.yml - resource: monolog.yml - resource: twig.yml - resource: imagine.yml
  5. Semantic Configuration: Don't Do It services.xml/yml + *Extension.php + Configuration.php

    http://symfony2-document.readthedocs.org/en/latest/cookbook/bundles/extension.html
  6. Annotations for Doctrine mappings /** @MongoDB\Document */ class Topic {

    /** @MongoDB\Id */ protected $id; /** @MongoDB\String */ protected $name; /** @MongoDB\Int */ protected $code; // .... }
  7. Data Fixtures One fixture file per entity OrderedFixtureInterface DoctrineFixturesBundle +

    Alice & bundle + Faker https://github.com/doctrine/DoctrineFixturesBundle https://github.com/hautelook/AliceBundle https://github.com/fzaninotto/Faker
  8. Make your controller extend the FrameworkBundle Get Request Submit form

    if any Call one Service method Return Response Rendering HTML far away
  9. Routing Configuration Annotations External format (YAML, XML) /** @Route("/") */

    public function indexAction() { } _index: pattern: / defaults: { _controller: AcmeBundle:Frontend:index }
  10. Store all your templates in app/Resources/views/ Inconsistently with Bundle coupling

    Hard to maintain Probably easier write template path Inside bundles In app/ DemoBunde:Default:index.html.twig default/index.html.twig ::layout.html.twig layout.html.twig AcmeDemoBundle::index.html.twig index.html.twig
  11. Use Form Types Define your forms as PHP classes class

    PostType extends AbstractType { public function buildForm( FormBuilderInterface $builder, array $options ) { $builder ->add('title') ->add('summary', 'textarea') ->add('content', 'textarea') ; }
  12. class PostType extends AbstractType { public function buildForm(// ...) {

    $builder // ... ->add('save', 'submit', array('label' => 'Create Post')) ; } Wrong code example “Add buttons in the templates, not in the form classes or the controllers” Form Templates
  13. Handling Forms $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em =

    $this->getDoctrine()->getManager(); $em->persist($post); $em->flush(); } return $this->redirect(...);
  14. Use the XLIFF for your translation files Too Verbose Extra

    complexity Accidental complexity Inconsistently with service configs
  15. Translation files location “Store the translation files in the app/Resources/translations

    directory” Same issues as for templates Inconsistently with Bundle coupling
  16. Translation Keys “Always use keys for translations instead of content

    strings” At form types At templates At validation messages
  17. Firewalls “Be simple: use only one firewall entry with the

    anonymous key enabled” Remember about API auth
  18. Password hashing “Use the bcrypt encoder for encoding your users

    passwords” security: encoders: AppBundle\Entity\User: bcrypt For old Sf systems <2.3 https://github.com/elnur/ElnurBlowfishPasswordEncoderBundle
  19. Authorization Protecting broad URL patterns, use access_control access_control: - {

    path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/, roles: ROLE_ADMIN }
  20. Custom Voter class PostVoter extends AbstractVoter { const CREATE =

    'create'; const EDIT = 'edit'; protected function getSupportedAttributes() { return array(self::CREATE, self::EDIT); } protected function getSupportedClasses() { return array('AppBundle\Entity\Post'); } } For fine-grained restrictions, define a custom security voter
  21. For fine-grained restrictions, define a custom security voter protected function

    isGranted($attribute, $post, $user = null) { if (!$user instanceof UserInterface) return false; if ($attribute == self::CREATE && in_array(ROLE_ADMIN, $user->getRoles()) ) return true; if ($attribute == self::EDIT && $user->getEmail() === $post->getAuthorEmail() ) return true; return false; } Custom Voter
  22. Applying voter Custom Voter # app/config/services.yml services: post_voter: class: AppBundle\Security\PostVoter

    public: false tags: - { name: security.voter } /** * @Security("is_granted('edit', post)") */ public function editAction(Post $post)
  23. Authorization ACL For restricting access to any object by any

    user via an admin interface, use the Symfony ACL