рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рд╕рд┐рдореНрдлрдиреА 2 рдЗрдВрдЯрд░реНрдирд▓реНрд╕

рдкреЛрд╕реНрдЯ рдЗрд╕ рдкреНрд░рд╢реНрди рд╕реЗ рдкреНрд░реЗрд░рд┐рдд рд╣реИред рд╣рдо рдирд┐рдпрдВрддреНрд░рдХ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рд╕рд┐рдореНрдлрдиреА рдШрдЯрдирд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рддреЛ рдХреИрд╕реЗ, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рд╕рдм рдХрд╛рдо рдХрд░реЗрдЧрд╛:
  1. рдирд┐рдпрдВрддреНрд░рдХ рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдХрд╛рд░ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдЬрд╛рдХреНрд╕ рдПрдиреЛрдЯреЗрд╢рди рдмрдирд╛рдПрдВ
  2. рд╣рдо рдЗрд╕ рдПрдиреЛрдЯреЗрд╢рди рдХреЛ рдШрдЯрдирд╛рдУрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдВрдЧреЗред
  3. рд╣рдо рдПрдиреЛрдЯреЗрд╢рди рдореЗрдВ рдЪрдпрдирд┐рдд рдкреНрд░рдХрд╛рд░ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдХрд╛рд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВрдЧреЗ

рдореИрдВ рдЖрдкрдХреЛ рддреБрд░рдВрдд рдЪреЗрддрд╛рд╡рдиреА рджреЗрддрд╛ рд╣реВрдВ, рдХреЛрдб рд╕рд╣реА рд╣реЛрдиреЗ рдХрд╛ рдирд╛рдЯрдХ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдХреИрд╢рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдореИрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдж рдореЗрдВ рдЕрдзрд┐рдХ рдХрд╣реВрдВрдЧрд╛), рд▓реЗрдХрд┐рди рдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ, рд╕рдордЭ рдореЗрдВ рдЖ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдк рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ Symfony2 рдЗрдВрдЯрд░рдиреЗрд╢рдирд▓ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред

рддреЛ, рдЪрд▓реЛред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдиреЛрдЯреЗрд╢рди рд╡рд░реНрдЧ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:
namespace SomeNamespace\SomeBundle\Annotations; /** @Annotation */ class Ajax { /** * @var array @contentType */ public $contentType; /** * @var array @parameters */ public $parameters; public function __construct($data) { if (isset($data['value'])) { $this->contentType = $data['value']; } if (isset($data['parameters'])) { $this->parameters = $data['parameters']; } } /** * @param array $contentType */ public function setContentType($contentType) { $this->contentType = $contentType; } /** * @return array */ public function getContentType() { return $this->contentType; } } 

рдпрд╣ рдПрдиреЛрдЯреЗрд╢рди рдирд┐рдпрдВрддреНрд░рдХ рджреНрд╡рд╛рд░рд╛ рджреА рдЧрдИ рд╕рд╛рдордЧреНрд░реА рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИред
рдЕрдЧрд▓рд╛, рдПрдХ рдИрд╡реЗрдВрдЯ рд╢реНрд░реЛрддрд╛ рдмрдирд╛рдПрдВ:
 namespace SomeNamespace\SomeBundle\Event; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Doctrine\Common\Annotations\Reader; use Symfony\Component\HttpFoundation\Response; /** * Controller Event listener */ class ControllerListener { /** * @var ServiceContainer */ private $container; /** * Parameters of Event Listener * * @var array */ private $parameters; /** * @var AnnotationsReader */ private $annotationReader; //     -   Core/ContentTypes public function __construct($c, $a) { $this->container = $c; $this->annotationReader = $a; //@TODO   ,        . ,    -      ,   . $classes = array(); $namespace = 'SomeNamespace\SomeBundle'; $namespace = str_replace('\\', '/', $namespace); $dir = opendir('../src/' . $namespace . '/Core/ContentTypes'); while ($classes[] = str_replace('.php', '', readdir($dir))) { ; } foreach ($classes as $key => $class) { if ($class == '') { unset($classes[$key]); continue; } if ($class[0] == '.') { unset($classes[$key]); } } $this->parameters['contentTypes'] = $classes; } /** * Controller event listener * * @param \Symfony\Component\HttpKernel\Event\KernelEvent $event */ public function onKernelController(KernelEvent $event) {//      .     .    ,     ,    ,        $controller = $event->getController(); $object = new \ReflectionObject($controller[0]); $method = $object->getMethod($controller[1]); $annotations = $this->annotationReader->getMethodAnnotations($method); $response = new Response(); $this->parameters['attributes'] = $event->getRequest()->attributes; foreach ($annotations as $annotation) { if ($annotation instanceof \ITE\JSBundle\Annotations\Ajax) { $this->parameters['annotation'] = $annotation; } } $class = NULL; $params = array(); if (isset($this->parameters['annotation'])) { if (isset($this->parameters['annotation']->parameters)) { $params = $this->parameters['annotation']->parameters; } foreach ($this->parameters['contentTypes'] as $contentType) { $className = '\ITE\JSBundle\Core\ContentTypes\\' . $contentType; $name = $className::getName(); if ($name == $this->parameters['annotation']->contentType) { $class = $className; } } if (!$class) { throw new \ITE\JSBundle\Core\Exception\ContentTypeException( 'ContentType "' . $this->parameters['annotation']->contentType . '" is not found!'); } //  -    .     . $contentType = new $class($this->container, $params); $this->parameters['contentType'] = $contentType; $contentType->hookPre($event->getRequest()); } } /** * Controller Response listener * * @param $event */ public function onKernelResponse($event) {//       .     javascript  , ,    Symfony Profiler.        $response = $event->getResponse(); $response = $this->addJavascript($response); $event->setResponse($response); } /** * Controller Request listener * * @param $event */ public function onKernelRequest($event) { //    .      $this->generateRoutes(); } /** * Controller response listener * * @param GetResponseForControllerResultEvent $event */ public function onKernelView(GetResponseForControllerResultEvent $event) { //     .    onKernelResponse if (isset($this->parameters['contentType'])) { $contentType = $this->parameters['contentType']; $response = new Response; $response->setContent($contentType->encodeParameters($event->getControllerResult())); $response = $contentType->hookPost($response); $event->setResponse($response); } } /** * Generating route array and move to javascript file */ private function generateRoutes() { //  ,       $routeCollection = $this->container->get('router')->getRouteCollection(); $routes = array(); foreach ($routeCollection->all() as $route) { $r = array(); $defaults = $route->getDefaults(); try { $method = new \ReflectionMethod($defaults['_controller']); } catch (\Exception $e) { continue; } $ann = $this->annotationReader->getMethodAnnotations($method); foreach ($ann as $a) { if ($a instanceof \Sensio\Bundle\FrameworkExtraBundle\Configuration\Route) { $r[$a->getName()] = $route->getPattern(); } } $routes += $r; } $path = __FILE__; $path = str_replace('Event' . DIRECTORY_SEPARATOR . 'ControllerListener.php', '', $path); $path .= 'Resources' . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . 'routing_template.js'; $content = file_get_contents($path); $route_string = json_encode($routes); $content = str_replace('__routes__', $route_string, $content); $kernel = $this->container->get('kernel'); $params = array( 'env' => $kernel->getEnvironment(), 'debug' => $kernel->isDebug(), 'name' => $kernel->getName(), 'startTime' => $kernel->getStartTime(), ); $content = str_replace('__params__', json_encode($params), $content); $path = str_replace('routing_template', 'routing', $path); file_put_contents($path, $content); } /** * Adding global Symfony javascript * * @param $response * * @return mixed */ private function addJavascript($response) {//       $content = $response->getContent(); $arr = explode('</head>', $content); if (count($arr) == 1) { return $response; } $twig = $this->container->get('templating'); $c = $twig->render('SomeNamespaceSomeBundle:Javascript:js.html.twig'); $content = $arr[0] . $c . "</head>" . $arr[1]; $response->setContent($content); return $response; } } 

рдФрд░ рдЗрд╕реЗ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ:
 #SomeBundle\Resources\config\services.yml services: my.ajax.listener: class: "SomeNamespace\SomeBundle\Event\ControllerListener" tags: [{name: kernel.event_listener, event: kernel.response, method: onKernelResponse, priority: -128}, {name: kernel.event_listener, event: kernel.request, method: onKernelRequest}, {name: kernel.event_listener, event: kernel.view, method: onKernelView, priority: -128}, {name: kernel.event_listener, event: kernel.controller, method: onKernelController}] arguments: [@service_container, @annotation_reader] 

рдПрдХ рдФрд░ рддрд░реНрдХ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ: рдкреНрд░рд╛рдердорд┐рдХрддрд╛ред рдпрд╣ рдШрдЯрдирд╛ рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рддрдп рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рджреНрд░реБрдкрд╛рд▓ рдореЗрд░реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрдпрд╛ред рдпрд╣ рдореЙрдбреНрдпреВрд▓ рд╡рдЬрди рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рдмрд╕ рд╡рд┐рдкрд░реАрддред рджреНрд░реБрдкрд╛рд▓ рдореЗрдВ, рдЕрдзрд┐рдХ рд╡рдЬрди, рдмрд╛рдж рдореЗрдВ рд╣реБрдХ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдФрд░ рд╕рд┐рдореНрдлрдиреА рдореЗрдВ, рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдЬрд┐рддрдиреА рдЕрдзрд┐рдХ рд╣реЛрдЧреА, рдкрд╣рд▓реЗ рдХреА рдШрдЯрдирд╛ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рддреЛ, рдкреНрд░рддреНрдпреЗрдХ рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдХрд╛рд░ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреНрдпрд╛ рджрд┐рдЦрддреА рд╣реИ:
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛рдПрдБ:

 namespace SomeNamespace\SomeBundle\Core; interface ContentTypeInterface { /** * Get the name of ContentType * @abstract * @return mixed */ public static function getName(); /** * Encoder * @abstract * @param $data * @return mixed */ public function encodeParameters($data); /** * Decoder * @abstract * @param $data * @return mixed */ public function decodeParameters($data); /** * Prepares request * @abstract * @param Request * @return mixed */ public function hookPre($request); /** * Changes response * @abstract * @param Response * @return mixed */ public function hookPost($response); } 

рдФрд░ рдЕрдм рдореИрдВ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдмрддрд╛рдКрдВрдЧрд╛:

рдЕрдЧрд▓рд╛, рд╣рдо рдПрдХ рд╡рд░реНрдЧ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рд╣рдорд╛рд░реЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рд╕рднреА рд╕рд╛рдордЧреНрд░реА рдкреНрд░рдХрд╛рд░ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреЗ:
 namespace SomeNamespace\SomeBundle\Core; class ContentType implements ContentTypeInterface { /** * @var ServiceContainer */ protected $container; /** * @var array parameters */ protected $parameters; /** * Public constructor * @param $container */ public function __construct($container, $params = array()){ $this->container = $container; $this->parameters = $params; } /** * Get the name of ContentType * @return mixed */ public static function getName() { return 'contentType'; } /** * Encoder * @param $data * @return mixed */ public function encodeParameters($data) { return $data; } /** * Decoder * @param $data * @return mixed */ public function decodeParameters($data) { return $data; } /** * Prepares request * @param $data * @return mixed */ public function hookPre($request) { } /** * Changes response * @param $data * @return mixed */ public function hookPost($response) { return $response; } } 

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ ContentTypeInterface рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред
рдЕрдм рдЖрдк рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдХрдВрдЯреЗрдВрдЯ-рдкреНрд░рдХрд╛рд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЕрдкрдирд╛ json рдХрдВрдЯреЗрдВрдЯ-рдЯрд╛рдЗрдк рджреВрдВрдЧрд╛:
 namespace SomeNamespace\SomeBundle\Core\ContentTypes; use SomeNamespace\SomeBundle\Core\ContentType; class JSONContentType extends ContentType { private $params; /** * Get the name of ContentType * @return mixed */ public static function getName() { return "json"; } /** * Changes response * @param $data * @return mixed */ public function hookPost($response) { return $response; } /** * Encoder * @param $data * @return mixed */ public function encodeParameters($data) { return json_encode($data); } /** * Decoder * @param $data * @return mixed */ public function decodeParameters($data) { return json_decode($data); } } 


рдЕрдВрдд рдореЗрдВ, рдореИрдВ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рджреВрдВрдЧрд╛ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдорд╛рд░реНрдЧреЛрдВ рдФрд░ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:

 //SomeBundle\Resources\js\routing_template.js (function(){if(typeof SF!='undefined'){SF.sSet('routes',__routes__);SF.parameters = __params__;}})(); 

рдФрд░ рдЗрд╕ рдкреВрд░реА рдЪреАрдЬрд╝ рдХреЛ рд╕рд╣реЗрдЬрдиреЗ рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рднреА:
 (function () { SF = function () { }; SF.prototype.fn = SF.prototype; SF = new SF(); SF.fn.Storage = {}; SF.fn.hasValue = function (name) { return this.Storage[name] !== undefined; }; SF.fn.getValue = function (name) { if (this.hasValue(name)) { return this.Storage[name]; } else { return void 0; } }; SF.fn.getAllValues = function () { return this.Storage }; SF.fn.loggingEnabled = function () { return this.parameters.debug; }; SF.fn.messagingEnabled = function () { return this.parameters.messaging !== undefined && this.parameters.messaging; }; SF.fn.getMessages = function () { return !this.framework || this.framework.messaging === undefined ? { } : this.framework.messaging; }; // framework SF.fn.getLocation = function (name) { if (this.hasLocation(name)) { return this.framework.ajax[name]; } else { return void 0; } }; SF.fn.hasLocation = function (name) { return this.framework !== null && this.framework.ajax !== undefined && this.framework.ajax[name] !== undefined; }; // Storage setter and getter SF.fn.sSet = function (key, val) { this.Storage[key] = val; }; SF.fn.sGet = function (key) { return this.Storage[key] ? this.Storage[key] : null; }; // log function with debug checking SF.fn.l = function (a, b) { if (!b) b = 'log'; if (this.parameters.debug) { switch (b) { case 'log': console.log('[SF]: ', a); break; case 'info': console.info('[SF]: ', a); break; case 'warning': console.warn('[SF]: ', a); break; case 'error': console.error('[SF]: ', a); break; } } }; // SF path function SF.fn.path = function (name, arguments) { if (this.Storage.routes[name]) { var path = this.Storage.routes[name]; for (var a in arguments) { path = path.replace('{' + a + '}', arguments[a]); } return path; } else { this.l('Route "' + name + '" is not found!', 'error'); return false; } }; })(window); 

рдЦреИрд░, рдЕрдм, рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдХрд╛рдо рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ рдПрдХ рдХреНрд░рд┐рдпрд╛ рдмрдирд╛рдПрдБ:
 //   use  ,  Symfony    /** * * @param key string * @Route("/ajax/{key}", name="JSBundle_ajax") * @Ajax("json") * @return array */ public function ajaxAction($key) { //do some work return array('a' => 'b', 'd' => 'c'); } 

рдирд┐рдпрдВрддреНрд░рдХ рдХреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЗрд╕ рддрд░рд╣ рд╣реЛрдЧреА:
 { a: "b", d: "c" } 

рднреА, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрджрд╛рд╣рд░рдг:
 SF.l(SF.path('JSBundle_ajax', {'key': 'asd'})); 

рдпрджрд┐ Symfony рдореЗрдВ рдбрд┐рдмрдЧ рдЕрдХреНрд╖рдо рд╣реИ, рддреЛ рдХреБрдЫ рднреА рдХрдВрд╕реЛрд▓ рдкрд░ рдкреНрд░рд┐рдВрдЯ рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдЕрдиреНрдпрдерд╛ рдпрд╣ рдкреНрд░рд┐рдВрдЯ рд╣реЛрдЧрд╛:
/ рдЕрдЬрд╛рдХреНрд╕ / рдЕрд╕рдж

PS рдРрдб-рдСрди рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред рдореБрдЭреЗ рдЪрддреБрд░ рд╡рд┐рдЪрд╛рд░ рд╕реБрдирдХрд░ рдкреНрд░рд╕рдиреНрдирддрд╛ рд╣реЛрдЧреАред

Source: https://habr.com/ru/post/In149378/


All Articles