Upload
michele-orselli
View
111
Download
5
Tags:
Embed Size (px)
DESCRIPTION
Symfony2 è sicuramente uno dei framework migliori in circolazione, ma non sono tutte rose e fiori, soprattutto per chi inizia a sviluppare ed è alle prime armi. In questa presentazione vorrei condividere la mie esperienza di apprendimento ed utilizzo del framework, cercando di mettere in evidenza i miei momenti wtf e alcune linee guida per sviluppare applicazioni manutenibili
Citation preview
My Symfony WTF
why a talk on WTF?
Why a talk on WTF?
why a talk on WTF?
I ♥
why a talk on WTF?
but...
why a talk on WTF?
why a talk on WTF?
why a talk on WTF?
why a talk on WTF?
the (old) times?
symfony 1 was focused onRapid Application Development
the shiny new thing
Symfony2 is focused on Application Development
the shiny new thing
the shiny new thing
the shiny new thing
speed as selling point
installation
create-project symfony/framework-standard-edition ./foo 2.3.0
cache/log permissions
cache/log permissions
cache/log permissions
php app/console cache:clear
cache/log permissions
cache all the things (in dev too)!
cache all the things (in dev too)!
http://symfony.com/doc/current/book/templating.html
user session in cache!
config.yml:
twig: cache: false
uhm, wait a minute...
user session in cache!
user session in cache!
capifony?
idephix? :-P
user session in cache!
config.yml:
framework: session: save_path: "%kernel.root_dir%/sessions/"
sf2 in da cloud
sf2 in da cloud
sf2 in da cloud
http://www.ideato.it/planet-ideato/symfony2-su-google-app-engine/
symfony2 needs a writable filesystemsymfony2 uses some restricted functionsyou can warmup cache, but paths are absolutethe problem is not only limited to symfony (eg: assetic)
sf2 in da cloud
annotations
/** * @ORM\Entity(repositoryClass="Ideato\OfferBundle\Repository\CityRepository") * @ORM\Table(name="city") */class City{ /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id;
/** * @ORM\Column(type="string", length=255) * @Assert\NotBlank() */ private $name;
annotations
use Doctrine\ORM\Mapping as ORM;use Symfony\Component\Validator\Constraints as Assert;
/** * @ORM\Entity(repositoryClass="Ideato\OfferBundle\Repository\CityRepository") * @ORM\Table(name="city") */class City{ /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id;
/** * @ORM\Column(type="string", length=255) * @Assert\NotBlank() */ private $name;
do you need everything?
@ParamConverter
do you need everything?
/** * @ParamConverter("post", class="SensioBlogBundle:Post") */public function showAction(Post $post){ ...}
do you need everything?
/** * @ParamConverter("post", class="SensioBlogBundle:Post") */public function showAction(Post $post){ ...}
public function showAction(Post $post){ ...}
do you need everything?
/** * @ParamConverter("post", class="SensioBlogBundle:Post") */public function showAction(Post $post){ ...}
public function showAction(Post $post){ ...}
public function showAction(Post $post, Comment $comment){ ...}
kill the magic?
/** * @ParamConverter("post", class="SensioBlogBundle:Post") */public function showAction(Post $post){ ...}
public function showAction(Post $post){ ...}
public function showAction(Post $post, Comment $comment){ ...}
explicit vs implicit
public function showAction($post_id){ $post = $this->getRepository(‘Posts’)
->findOneById($post_id);}
if u can it doesn’t mean you have to
use Doctrine\DBAL\Types\Type;use Doctrine\DBAL\Platforms\AbstractPlatform; /** * NewObject datatype */class NewObjectType extends Type{ public function convertToPHPValue($value, AbstractPlatform $platform) { $listeners = $platform -> getEventManager() -> getListeners('getContainer'); $listener = array_shift($listeners); $container = $listener -> getContainer(); return $container -> get('service'); }}
passing around the DIC is bad
class A{ protected $first_service; protected $second_service;
public function __construct(ContainerInterface $container) { $this->first_service = $container->get(‘firstService’); $this->second_service = $container->get(‘secondService’); }}
passing around the DIC is bad
class A{ protected $first_service; protected $second_service;
public function __construct(FirstService $first, SecondService $second) { $this->first_service = $first; $this->second_service = $second; }}
in services.yml:
services: my.service: arguments: - "@first_service" - "@second_service" class: My\Class\A
everything is a bundle
configuration (Mopa)...
mopa_bootstrap: version: ~ form: templating: MopaBootstrapBundle:Form:fields.html.twig horizontal_label_class: col-lg-3 horizontal_input_wrapper_class: col-lg-9 row_wrapper_class: form-group render_fieldset: true render_collection_item: true show_legend: true show_child_legend: false checkbox_label: both render_optional_text: true render_required_asterisk: false error_type: ~ tooltip: icon: icon-info-sign placement: top tabs: class: nav nav-tabs popover: icon: icon-info-sign placement: top collection: widget_remove_btn: attr: class: btn icon: ~ icon_color: ~ widget_add_btn: attr: class: btn icon: ~ icon_color: ~ navbar: template: MopaBootstrapBundle:Navbar:navbar.html.twig initializr: meta: title: MopaBootstrapBundle description: MopaBootstrapBundle keywords: MopaBootstrapBundle, Twitter Bootstrap, HTML5 Boilerplate author_name: My name author_url: # feed_atom: ~ feed_rss: ~ sitemap: ~ nofollow: false noindex: false dns_prefetch:
# Default: - //ajax.googleapis.com google: wt: ~ analytics: ~ diagnostic_mode: false
configuration (FosUserBundle)...
fos_user: db_driver: ~ # Required user_class: ~ # Required firewall_name: ~ # Required model_manager_name: ~ use_listener: true use_username_form_type: true from_email: address: [email protected] sender_name: webmaster profile: form: type: fos_user_profile name: fos_user_profile_form validation_groups:
# Defaults: - Profile - Default change_password: form: type: fos_user_change_password name: fos_user_change_password_form validation_groups:
# Defaults: - ChangePassword - Default registration: confirmation: enabled: false template: FOSUserBundle:Registration:email.txt.twig from_email: address: ~ # Required sender_name: ~ # Required form: type: fos_user_registration name: fos_user_registration_form validation_groups:
# Defaults: - Registration - Default
resetting: token_ttl: 86400 email: template: FOSUserBundle:Resetting:email.txt.twig from_email: address: ~ # Required sender_name: ~ # Required form: type: fos_user_resetting name: fos_user_resetting_form validation_groups:
# Defaults: - ResetPassword - Default service: mailer: fos_user.mailer.default email_canonicalizer: fos_user.util.canonicalizer.default token_generator: fos_user.util.token_generator.default username_canonicalizer: fos_user.util.canonicalizer.default user_manager: fos_user.user_manager.default template: engine: twig group: group_class: ~ # Required group_manager: fos_user.group_manager.default form: type: fos_user_group name: fos_user_group_form validation_groups:
# Defaults: - Registration - Default
configuration...
configuration is just another way of programming
configuration...
is there a way to create decoupled, maintainable code?
configuration...
libraries
ddd, code first, ...
src!"" Acme #"" CoreDomain $ !"" User $ #"" User.php $ #"" UserId.php $ !"" UserRepository.php !"" CoreDomainBundle #"" Repository $ !"" InMemoryUserRepository.php !"" AcmeCoreDomainBundle.php
http://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/http://whitewashing.de
Wrap up
wrap up
Wrap up
after all Symfony2 is just aframework
Wrap up
framework != architecture
Wrap up
do you need that feature?
Wrap up
think in advance
Wrap up
keep things decoupled
that’s all folks!
Thank you!@_orso_ [email protected]
that’s all folks!
Pics Creditswtf per minute: http://www.codinghorror.com/blog/2009/02/whos-your-coding-buddy.htmlpills: http://www.daygame.com/2013/blog/swallowing-the-red-pill/umarell: http://www.informarexresistere.fr/clouds: http://www.flickr.com/photos/uncle_jerry/49341110/gae: http://venturebeat.files.wordpress.com/2013/05/google-app-engine-php-zend.jpg