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

Symfony2 Components. Как не изобретать велосипед (DrupalCafe version)

101b5adab18a468a3dfe63f77980ccb9?s=47 Roma
March 02, 2013

Symfony2 Components. Как не изобретать велосипед (DrupalCafe version)

DrupalCafe #3 Spb
Не изобретайте велосипеды, катайтесь на них, улучшайте их, получайте удовольствие и не тратьте время зря. Фреймворк Symfony2 предоставляет отличный набор независимых компонентов для различных задач веб-разработки. Давайте посмотрим, как можно их использовать для решения наших задач.

101b5adab18a468a3dfe63f77980ccb9?s=128

Roma

March 02, 2013
Tweet

Transcript

  1. Symfony2 Components. Как не изобретать велосипед Роман Лапин, Evercode Lab

    @memphys, roma@evercodelab.com
  2. Symfony2 Components. Как не изобретать велосипед Роман Лапин, Evercode Lab

    @memphys, roma@evercodelab.com Обновлено и адаптировано специально для DrupalCafe #3 ;)
  3. None
  4. Don’t Reinvent The Wheel, Unless You Plan on Learning More

    About Wheels. Jeff Atwood http:/ /www.codinghorror.com/blog/2009/02/dont-reinvent-the-wheel-unless-you-plan-on-learning- more-about-wheels.html
  5. None
  6. PHP < 5.3 Много библиотек, фреймворков и вообще готового кода

    Большое коммьюнити PEAR (это боль) НО! Copy + Paste :(
  7. Обмениваться кодом, находить готовые решения и переисользовать код было больно,

    грустно и местами противно.
  8. PHP >= 5.3 Namespaces (наконец-то!) PHP Framework Interop Group Стандарты

    Composer Прогресс Спасибо, GitHub!
  9. Это надо знать http:/ /www.phptherightway.com/ http:/ /www.php-fig.org/ PSR-0 ... PSR-3

    http:/ /getcomposer.org/ https:/ /packagist.org/
  10. Это надо знать. PSR-0 \Symfony\Core\Request /path/to/project/lib/vendor/Symfony/Core/ Request.php \Zend\Mail\Message /path/to/project/lib/vendor/Zend/Mail/ Message.php

  11. Symfony?

  12. Symfony2!

  13. Symfony Components Beside being a full-stack framework, Symfony is also

    a set of decoupled and standalone components. Symfony Components implement common features needed to develop websites.
  14. Symfony2+Drupal=<3 Today, I want to officially announce that Drupal will

    adopt some of the Symfony Components for their upcoming version 8. And I'm not talking about some minor components, they are embracing our vision and they will use the major components that will allow them to build a great low-level architecture for Drupal 8: HttpFoundation, HttpKernel, Routing, EventDispatcher, DependencyInjection, and ClassLoader. Fabien Potencier - March 22, 2012 http:/ /symfony.com/blog/symfony2-meets-drupal-8
  15. Компоненты ClassLoader Config DependencyInjection EventDispatcher HttpFoundation HttpKernel Routing Templating BrowserKit

    Process Console Finder CssSelector DomCrawler Form Locale Serializer Yaml Validator Translation
  16. Компоненты ClassLoader Config DependencyInjection EventDispatcher HttpFoundation HttpKernel Routing Templating BrowserKit

    Process Console Finder CssSelector DomCrawler Form Locale Serializer Yaml Validator Translation
  17. Компоненты в Drupal8 ClassLoader Config DependencyInjection EventDispatcher HttpFoundation HttpKernel Routing

    Templating BrowserKit Process Console Finder CssSelector DomCrawler Form Locale Serializer Yaml Validator Translation
  18. Причины Независимые и изолированные Покрыты тестами Очень приятный API Широкое

    распространение Проведен независимый аудит безопасности
  19. Установка Git Pear Composer

  20. Установка Git Pear — больше никогда! Composer

  21. Установка { "require": { "symfony/console": "2.1.*", "symfony/process": "2.1.*", "symfony/finder": "2.1.*",

    "symfony/form": "2.1.*", "symfony/validator": "2.1.*", "symfony/config": "2.1.*", "symfony/translation": "2.1.*", "symfony/security": "2.1.*" ... } } $ composer install require_once __DIR__.'/../vendor/autoload.php';
  22. { "name": "drupal/drupal", "description": "Drupal is an open source content

    management platform powering millions of websites and applications.", "license": "GPL-2.0+", "repositories": [{ "type": "vcs", "url": "https://github.com/msonnabaum/phpunit.git" } ], "require": { "symfony/class-loader": "2.2.0-BETA2", "symfony/dependency-injection": "2.2.0-BETA2", "symfony/event-dispatcher": "2.2.0-BETA2", "symfony/http-foundation": "2.2.0-BETA2", "symfony/http-kernel": "2.2.0-BETA2", "symfony/routing": "2.2.0-BETA2", "symfony/serializer": "2.2.0-BETA2", "symfony/validator": "2.2.0-BETA2", "symfony/yaml": "2.2.0-BETA2", "twig/twig": "1.12.1", "doctrine/common": "2.3.0", "guzzle/http": "3.1.0", "kriswallsmith/assetic": "1.1.0-alpha1", "symfony-cmf/routing": "dev-master#ea4a10", "easyrdf/easyrdf": "0.8.0-beta.1", "phpunit/phpunit": "3.7 as dev-3.7" }, "minimum-stability": "dev" }
  23. ClassLoader The ClassLoader Component loads your project classes automatically if

    they follow some standard PHP conventions. { "require": { "symfony/class-loader": "2.2.0-BETA2", } }
  24. ClassLoader require_once '/path/to/src/Symfony/Component/ClassLoader/ UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader();

    // You can search the include_path as a last resort. $loader->useIncludePath(true); // ... register namespaces and prefixes here - see below $loader->register();
  25. ClassLoader $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/../vendor/symfony/symfony/src', 'Monolog' => __DIR__.'/../vendor/monolog/monolog/src', )); $loader->registerPrefixes(array(

    'Swift_' => __DIR__.'/vendor/swiftmailer/swiftmailer/ lib/classes', 'Twig_' => __DIR__.'/vendor/twig/twig/lib', ));
  26. HttpFoundation The Symfony2 HttpFoundation component replaces these default PHP global

    variables and functions by an Object-Oriented layer. { "require": { "symfony/http-foundation": "2.2.0-BETA2", } }
  27. HttpFoundation use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); $input = $request->get('name', 'World');

    // the URI minus any query parameters $request->getPathInfo(); // retrieve SERVER variables $request->server->get('HTTP_HOST'); // retrieves an instance of UploadedFile identified by foo $request->files->get('foo');
  28. HttpFoundation // COOKIE value $request->cookies->get('PHPSESSID'); // HTTP request header $request->headers->get('host');

    $request->getMethod(); // GET, POST, PUT, DELETE, HEAD // simulate a request $request = Request::create('/awesome.php?say=wooohooo');
  29. HttpFoundation use Symfony\Component\HttpFoundation\Response; $response = new Response(); $response->setContent(“What’s up, Doc?”);

    $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/html'); // HTTP cache headers $response->setMaxAge(10);
  30. Routing The Routing Component maps an HTTP request to a

    set of configuration variables. { "require": { "symfony/routing": "2.2.0-BETA2", } }
  31. Routing use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $route

    = new Route( '/archive/{month}', // path array('controller' => 'showArchive'), // default values array('month' => '[0-9]{4}-[0-9]{2}'), // requirements array() // options ); $routes = new RouteCollection(); $routes->add('route_name', $route); $context = new RequestContext($_SERVER['REQUEST_URI']); $matcher = new UrlMatcher($routes, $context); $parameters = $matcher->match('/archive/2012-01'); // array('controller' => 'showArchive', '_route' => 'route_name')
  32. HttpKernel HttpKernel provides the building blocks to create flexible and

    fast HTTP-based frameworks. { "require": { "symfony/http-kernel": "2.2.0-BETA2", } }
  33. HttpKernelInterface interface HttpKernelInterface { /** * Handles a Request to

    convert it to a Response. * * @param Request $request A Request instance * * @return Response A Response instance */ function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true); }
  34. HttpKernelInterface $routes = new RouteCollection(); $routes->add('hello', new Route('/hello', array('_controller' =>

    function (Request $request) { return new Response(sprintf("Hello %s", $request->get('name'))); } ))); $request = Request::createFromGlobals(); $context = new RequestContext(); $context->fromRequest($request); $matcher = new UrlMatcher($routes, $context); $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber(new RouterListener($matcher)); $resolver = new ControllerResolver(); $kernel = new HttpKernel($dispatcher, $resolver); $kernel->handle($request)->send();
  35. Finder The Finder Component finds files and directories via an

    intuitive fluent interface. { "require": { "symfony/finder": "2.2.0-BETA2", } }
  36. Finder use Symfony\Component\Finder\Finder; $finder = new Finder(); $finder->files() ->in(__DIR__) ->in(__DIR__.'/../data')

    ->exclude('crap') ; foreach ($finder as $file) { print $file->getRealpath()."\n"; print $file->getFilename()."\n"; }
  37. Finder // files or directories $finder->files(); $finder->directories(); $finder->files()->followLinks(); $finder->ignoreVCS(false); //

    sorting $finder->sortByName(); $finder->sortByType();
  38. Finder // filtering $finder->files()->name('*.bugs'); $finder->files()->notName('*.bunny'); $finder->files()->contains('/ehhhh\s+what$/i'); $finder->files()->size('>= 1K')->size('<= 42K'); $finder->date('since

    yesterday'); $finder->depth('== 0');
  39. Console The Console component allows you to create command-line commands.

    Your console commands can be used for any recurring task, such as cronjobs, imports, or other batch jobs. { "require": { "symfony/console": "2.2.0-BETA2", } }
  40. Console #!/usr/bin/env php <?php use Symfony\Component\Console\Application; use App\Command\ParseCommand; $console =

    new Application(); $console->add(new ParseCommand()); $console->run();
  41. Console

  42. Console namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use

    Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface;
  43. Console class ParseCommand extends Command { protected function configure() {

    $this ->setName('parse') ->setDescription('Parses cached information') ->addArgument('date', InputArgument::OPTIONAL, "Put in some date.", date('Y-m-d')) ; } }
  44. Console protected function execute(InputInterface $input, OutputInterface $output) { $date =

    $input->getArgument('date'); if (empty($date)) { $date = date('Y-m-d'); } $formatter = new CsvFormatter(); $formatter->process($date); $output->writeln('<info>operation finished</info>'); }
  45. Form Form provides tools for defining forms, rendering and binding

    request data to related models. Furthermore it provides integration with the Validation component. { "require": { "symfony/form": "2.2.0-BETA2", } }
  46. Form namespace App\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints as

    Assert; use Symfony\Component\OptionsResolver\OptionsResolverInterface; class RegisterType extends AbstractType { ... public function getName() { return 'register'; } }
  47. Form public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('event',

    'choice', array( 'choices' => $events, 'constraints' => new Assert\Choice(array_keys($events)), 'required' => true, 'attr' => array( 'class' => 'input-xlarge' ), )) ->add('first_name', 'text', array( 'constraints' => new Assert\NotBlank(), 'required' => true, )) }
  48. Form $app->match('/', function (Request $request) use ($app) { $form =

    $app['form.factory']->create( new RegisterType($app['event_service']) ); if ('POST' == $request->getMethod()) { $form->bind($request); if ($form->isValid()) { $data = $form->getData(); // ... return $app->redirect('success'); } } return $app['twig']->render('index.html.twig', array( 'form' => $form->createView() )); });
  49. Form <form action="/" method="post" novalidate> {{ form_widget(form) }} <input type="submit"

    name="submit" value="Submit" /> </form>
  50. Twig The flexible, fast, and secure template engine for PHP

    { "require": { "twig/twig": "1.12.1", } }
  51. Twig <?php echo $var ?> <?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8')

    ?> {{ var }} {{ var|escape }} {% for user in users %} * {{ user.name }} {% else %} No user have been found. {% endfor %} {% extends "layout.html" %} {% block content %} Content of the page... {% endblock %}
  52. Где применять? Рефакторинг Новые приложения Интеграция в существующий код Велосипеды,

    говорите? ;) Ваши варианты
  53. Что-нибудь еще? EventDispatcher (https:/ /speakerdeck.com/ nucleartux/symfony-event-dispatcher) DependencyInjection (https:/ / speakerdeck.com/toothfairy/inversion-of-

    control-in-symfony-2) http:/ /symfony.com/components
  54. Что-нибудь еще? Silex (http:/ /silex.sensiolabs.org/) Twig (http:/ /twig.sensiolabs.org/) SwiftMailer (http:/

    /swiftmailer.org/) KnpBundles (http:/ /knpbundles.com/) Symfony2 CMF (http:/ /cmf.symfony.com/)
  55. Источники http:/ /symfony.com/components “Create your own framework... on top of

    the Symfony2 Components” by Fabien Potencier Source code http:/ /www.php-fig.org/ https:/ /igor.io/
  56. Reinvent away. Most of our current technology sucks, and even

    if it didn't, who am I to try and stop you? Bob Lee (http:/ /blog.crazybob.org/2007/09/why-reinvent-wheel.html)
  57. We wanted flying cars— instead we got 140 characters. Peter

    Thiel
  58. And one more thing

  59. Будьте не просто Drupal разработчиком, или Symfony разработчиком, или даже

    PHP или Ruby разработчиком. Смотрите шире, обменивайтесь идеями, ищите решения действительно важных и новых проблем.
  60. None
  61. Спасибо! Рома Лапин Evercode Lab roma@evercodelab.com @memphys @evercodelab