1<?php
2/*
3 +------------------------------------------------------------------------+
4 | Phalcon Framework                                                      |
5 +------------------------------------------------------------------------+
6 | Copyright (c) 2011-2017 Phalcon Team (https://phalconphp.com)          |
7 +------------------------------------------------------------------------+
8 | This source file is subject to the New BSD License that is bundled     |
9 | with this package in the file LICENSE.txt.                             |
10 |                                                                        |
11 | If you did not receive a copy of the license and are unable to         |
12 | obtain it through the world-wide-web, please send an email             |
13 | to license@phalconphp.com so we can send you a copy immediately.       |
14 +------------------------------------------------------------------------+
15 */
16
17namespace Phalcon\Test\Unit\Mvc;
18
19use Phalcon\Mvc\Micro;
20use Phalcon\Events\Event;
21use Phalcon\Events\Manager;
22use Phalcon\Di\FactoryDefault;
23use Phalcon\Test\Module\UnitTest;
24
25/**
26 * Phalcon\Test\Unit\Mvc\MicroTest
27 *
28 * Tests the Phalcon\Mvc\Micro component
29 *
30 * @package   Phalcon\Test\Unit\Mvc
31 */
32class MicroTest extends UnitTest
33{
34    /**
35     * Tests after binding event
36     *
37     * @author Wojciech Ślawski <jurigag@gmail.com>
38     * @since  2016-11-19
39     */
40    public function testAfterBindingEvent()
41    {
42        $this->specify(
43            'afterBinding event should be fired',
44            function () {
45                $di = new FactoryDefault();
46                $micro = new Micro($di);
47                $manager = new Manager();
48                $manager->attach(
49                    'micro:afterBinding',
50                    function (Event $event, Micro $micro) {
51                        return false;
52                    }
53                );
54                $micro->setEventsManager($manager);
55                $micro->get(
56                    '/test',
57                    function () {
58                        return 'test';
59                    }
60                );
61                expect($micro->handle('/test'))->isEmpty();
62            }
63        );
64    }
65
66    /**
67     * Tests after binding middleware
68     *
69     * @author Wojciech Ślawski <jurigag@gmail.com>
70     * @since  2016-11-19
71     */
72    public function testAfterBindingMiddleware()
73    {
74        $this->specify(
75            'afterBinding middleware should be called',
76            function () {
77                $di = new FactoryDefault();
78                $micro = new Micro($di);
79                $micro->afterBinding(
80                    function () {
81                        return false;
82                    }
83                );
84                $micro->get(
85                    '/test',
86                    function () {
87                        return 'test';
88                    }
89                );
90                expect($micro->handle('/test'))->equals('test');
91            }
92        );
93    }
94
95    public function testStopMiddlewareOnAfterBindingClosure()
96    {
97        $this->specify(
98            "afterBinding middleware doesn't work as expected",
99            function () {
100                $di = new FactoryDefault();
101                $micro = new Micro($di);
102                $micro->afterBinding(
103                    function () use ($micro) {
104                        $micro->stop();
105
106                        return false;
107                    }
108                );
109                $micro->get(
110                    '/test',
111                    function () {
112                        return 'test';
113                    }
114                );
115                expect($micro->handle('/test'))->isEmpty();
116            }
117        );
118    }
119
120    public function testStopMiddlewareOnAfterBindingClassFirst()
121    {
122        $this->specify(
123            "afterBinding middleware doesn't work as expected",
124            function () {
125                $di = new FactoryDefault();
126                $micro = new Micro($di);
127                $middleware = new \MyMiddleware();
128                $middlewareStop = new \MyMiddlewareStop();
129                $micro->afterBinding($middlewareStop);
130                $micro->afterBinding($middleware);
131                $micro->afterBinding($middleware);
132                $micro->afterBinding($middleware);
133                $micro->get(
134                    '/test',
135                    function () {
136                        return 'test';
137                    }
138                );
139                expect($micro->handle('/test'))->isEmpty();
140                expect($middlewareStop->getNumber())->equals(1);
141                expect($middleware->getNumber())->equals(0);
142            }
143        );
144    }
145
146    public function testStopMiddlewareOnAfterBindingClass()
147    {
148        $this->specify(
149            "afterBinding middleware doesn't work as expected",
150            function () {
151                $di = new FactoryDefault();
152                $micro = new Micro($di);
153                $middleware = new \MyMiddleware();
154                $middlewareStop = new \MyMiddlewareStop();
155                $micro->afterBinding($middleware);
156                $micro->afterBinding($middleware);
157                $micro->afterBinding($middleware);
158                $micro->afterBinding($middlewareStop);
159                $micro->afterBinding($middleware);
160                $micro->get(
161                    '/test',
162                    function () {
163                        return 'test';
164                    }
165                );
166                expect($micro->handle('/test'))->isEmpty();
167                expect($middleware->getNumber())->equals(3);
168                expect($middlewareStop->getNumber())->equals(1);
169            }
170        );
171    }
172
173    public function testMicroClass()
174    {
175        $this->specify(
176            "MVC Micro doesn't work as expected",
177            function () {
178                $handler = new \RestHandler();
179
180                $app = new Micro();
181
182                $app->get("/api/site", [$handler, "find"]);
183                $app->post("/api/site/save", [$handler, "save"]);
184                $app->delete("/api/site/delete/1", [$handler, "delete"]);
185
186                //Getting the url from _url using GET
187                $_SERVER["REQUEST_METHOD"] = "GET";
188                $_GET["_url"] = "/api/site";
189
190                $app->handle();
191
192                expect($handler->getNumberAccess())->equals(1);
193                expect($handler->getTrace())->equals(["find"]);
194
195                //Getting the url from _url using POST
196                $_SERVER["REQUEST_METHOD"] = "POST";
197                $_GET["_url"] = "/api/site/save";
198
199                $app->handle();
200
201                expect($handler->getNumberAccess())->equals(2);
202                expect($handler->getTrace())->equals(["find", "save"]);
203
204                //Passing directly a URI
205                $_SERVER["REQUEST_METHOD"] = "DELETE";
206                $_GET["_url"] = null;
207
208                $app->handle("/api/site/delete/1");
209
210                expect($handler->getNumberAccess())->equals(3);
211                expect($handler->getTrace())->equals(["find", "save", "delete"]);
212            }
213        );
214    }
215
216    /**
217     * Tests the notFound
218     *
219     * @issue T169
220     * @author Nikos Dimopoulos <nikos@niden.net>
221     * @since 2012-11-06
222     */
223    public function testMicroNotFoundT169()
224    {
225        $this->specify(
226            "MVC Micro notFound doesn't work",
227            function () {
228                $handler = new \RestHandler();
229
230                $app = new Micro();
231
232                $app->get("/api/site", [$handler, "find"]);
233                $app->post("/api/site/save", [$handler, "save"]);
234
235                $flag = false;
236
237                $app->notFound(
238                    function () use (&$flag) {
239                        $flag = true;
240                    }
241                );
242
243                $_SERVER["REQUEST_METHOD"] = "GET";
244                $_GET["_url"] = "/fourohfour";
245
246                $app->handle();
247
248                expect($flag)->true();
249            }
250        );
251    }
252
253    public function testMicroBeforeHandlers()
254    {
255        $this->specify(
256            "Micro::before event handlers don't work as expected",
257            function () {
258                $trace = [];
259
260                $app = new Micro();
261
262                $app->before(
263                    function () use ($app, &$trace) {
264                        $trace[] = 1;
265                        $app->stop();
266
267                        return false;
268                    }
269                );
270
271                $app->before(
272                    function () use ($app, &$trace) {
273                        $trace[] = 1;
274                        $app->stop();
275
276                        return false;
277                    }
278                );
279
280                $app->map(
281                    "/blog",
282                    function () use (&$trace) {
283                        $trace[] = 1;
284                    }
285                );
286
287                $app->handle("/blog");
288
289                expect($trace)->count(1);
290            }
291        );
292    }
293
294    public function testMicroAfterHandlers()
295    {
296        $this->specify(
297            "Micro::after event handlers don't work as expected",
298            function () {
299                $trace = [];
300
301                $app = new Micro();
302
303                $app->after(
304                    function () use (&$trace) {
305                        $trace[] = 1;
306                    }
307                );
308
309                $app->after(
310                    function () use (&$trace) {
311                        $trace[] = 1;
312                    }
313                );
314
315                $app->map(
316                    "/blog",
317                    function () use (&$trace) {
318                        $trace[] = 1;
319                    }
320                );
321
322                $app->handle("/blog");
323
324                expect($trace)->count(3);
325            }
326        );
327    }
328
329    public function testMicroAfterHandlersIfOneStop()
330    {
331        $this->specify(
332            "Micro::finish event handlers don't work as expected",
333            function () {
334                $trace = array();
335
336                $app = new Micro();
337
338                $app->after(
339                    function () use (&$trace) {
340                        $trace[] = 1;
341                    }
342                );
343
344                $app->after(
345                    function () use ($app, &$trace) {
346                        $trace[] = 1;
347                        $app->stop();
348                    }
349                );
350
351                $app->after(
352                    function () use (&$trace) {
353                        $trace[] = 1;
354                    }
355                );
356
357                $app->map(
358                    '/blog',
359                    function () use (&$trace) {
360                        $trace[] = 1;
361                    }
362                );
363
364                $app->handle('/blog');
365
366                expect($trace)->count(3);
367            }
368        );
369    }
370
371    public function testMicroFinishHandlers()
372    {
373        $this->specify(
374            "Micro::finish event handlers don't work as expected",
375            function () {
376                $trace = [];
377
378                $app = new Micro();
379
380                $app->finish(
381                    function () use (&$trace) {
382                        $trace[] = 1;
383                    }
384                );
385
386                $app->finish(
387                    function () use (&$trace) {
388                        $trace[] = 1;
389                    }
390                );
391
392                $app->map(
393                    "/blog",
394                    function () use (&$trace) {
395                        $trace[] = 1;
396                    }
397                );
398
399                $app->handle("/blog");
400
401                expect($trace)->count(3);
402            }
403        );
404    }
405
406    public function testMicroFinishHandlersIfOneStop()
407    {
408        $this->specify(
409            "Micro::finish event handlers don't work as expected",
410            function () {
411                $trace = array();
412
413                $app = new Micro();
414
415                $app->finish(
416                    function () use (&$trace) {
417                        $trace[] = 1;
418                    }
419                );
420
421                $app->finish(
422                    function () use ($app, &$trace) {
423                        $trace[] = 1;
424                        $app->stop();
425                    }
426                );
427
428                $app->finish(
429                    function () use (&$trace) {
430                        $trace[] = 1;
431                    }
432                );
433
434                $app->map(
435                    '/blog',
436                    function () use (&$trace) {
437                        $trace[] = 1;
438                    }
439                );
440
441                $app->handle('/blog');
442
443                expect($trace)->count(3);
444            }
445        );
446    }
447
448    public function testMicroEvents()
449    {
450        $this->specify(
451            "Micro event handlers don't work as expected",
452            function () {
453                $trace = [];
454
455                $eventsManager = new Manager();
456
457                $eventsManager->attach(
458                    'micro',
459                    function ($event) use (&$trace) {
460                        $trace[$event->getType()] = true;
461                    }
462                );
463
464                $app = new Micro();
465
466                $app->setEventsManager($eventsManager);
467
468                $app->map(
469                    "/blog",
470                    function () {
471                    }
472                );
473
474                $app->handle("/blog");
475
476                expect($trace)->equals(
477                    [
478                        'beforeHandleRoute' => true,
479                        'beforeExecuteRoute' => true,
480                        'afterExecuteRoute' => true,
481                        'afterHandleRoute' => true,
482                        'afterBinding' => true,
483                    ]
484                );
485            }
486        );
487    }
488
489    public function testMicroMiddlewareSimple()
490    {
491        $this->specify(
492            "Micro before/after/finish events don't work as expected",
493            function () {
494                $app = new Micro();
495
496                $app->map(
497                    "/api/site",
498                    function () {
499                        return true;
500                    }
501                );
502
503                $trace = 0;
504
505                $app->before(
506                    function () use (&$trace) {
507                        $trace++;
508                    }
509                );
510
511                $app->before(
512                    function () use (&$trace) {
513                        $trace++;
514                    }
515                );
516
517                $app->after(
518                    function () use (&$trace) {
519                        $trace++;
520                    }
521                );
522
523                $app->after(
524                    function () use (&$trace) {
525                        $trace++;
526                    }
527                );
528
529                $app->finish(
530                    function () use (&$trace) {
531                        $trace++;
532                    }
533                );
534
535                $app->finish(
536                    function () use (&$trace) {
537                        $trace++;
538                    }
539                );
540
541                $app->handle("/api/site");
542
543                expect($trace)->equals(6);
544            }
545        );
546    }
547
548    public function testMicroMiddlewareClasses()
549    {
550        $this->specify(
551            "Micro middleware events don't work as expected",
552            function () {
553                $app = new Micro();
554
555                $app->map(
556                    "/api/site",
557                    function () {
558                        return true;
559                    }
560                );
561
562                $middleware = new \MyMiddleware();
563
564                $app->before($middleware);
565                $app->before($middleware);
566
567                $app->after($middleware);
568                $app->after($middleware);
569
570                $app->finish($middleware);
571                $app->finish($middleware);
572
573                $app->handle("/api/site");
574
575                expect($middleware->getNumber())->equals(6);
576            }
577        );
578    }
579
580    public function testMicroStopMiddlewareOnBeforeClasses()
581    {
582        $this->specify(
583            "Micro middleware events don't work as expected",
584            function () {
585                $app = new Micro();
586
587                $app->map(
588                    "/api/site",
589                    function () {
590                        return true;
591                    }
592                );
593
594                $middleware = new \MyMiddlewareStop();
595
596                $app->before($middleware);
597                $app->before($middleware);
598
599                $app->after($middleware);
600                $app->after($middleware);
601
602                $app->finish($middleware);
603                $app->finish($middleware);
604
605                $app->handle("/api/site");
606
607                expect($middleware->getNumber())->equals(1);
608            }
609        );
610    }
611
612    public function testMicroStopMiddlewareOnAfterAndFinishClasses()
613    {
614        $this->specify(
615            "Micro middleware events don't work as expected",
616            function () {
617                $app = new Micro();
618
619                $app->map(
620                    '/api/site',
621                    function () {
622                        return true;
623                    }
624                );
625
626                $middleware = new \MyMiddlewareStop();
627
628                $app->after($middleware);
629                $app->after($middleware);
630
631                $app->finish($middleware);
632                $app->finish($middleware);
633
634                $app->handle('/api/site');
635
636                expect($middleware->getNumber())->equals(2);
637            }
638        );
639    }
640
641    public function testMicroResponseAlreadySentError()
642    {
643        $this->specify(
644            "Micro::handle method doesn't work as expected",
645            function () {
646                $app = new Micro();
647                $app->after(
648                    function () use ($app) {
649                        $content = $app->getReturnedValue();
650                        $app->response->setJsonContent($content)->send();
651                    }
652                );
653                $app->map(
654                    '/api',
655                    function () {
656                        return 'success';
657                    }
658                );
659                expect($app->handle('/api'))->equals('success');
660            }
661        );
662    }
663
664    public function testMicroCollectionVia()
665    {
666        $this->specify(
667            "Adding collection via doesn't work as exepected",
668            function () {
669                $app = new Micro();
670                $collection = new Micro\Collection();
671                $collection->setHandler(new \Test2Controller());
672                $collection->mapVia(
673                    "/test",
674                    'indexAction',
675                    ["POST", "GET"],
676                    "test"
677                );
678                $app->mount($collection);
679                expect($app->getRouter()->getRouteByName("test")->getHttpMethods())->equals(["POST", "GET"]);
680            }
681        );
682    }
683}
684