Dispatcher Phalcon

Phalcon \ MVC \ Dispatcher adalah komponen yang bertanggung jawab untuk membuat instance pengendali dan melaksanakan tindakan yang diperlukan  dalam aplikasi MVC. Memahami operasi dan kemampuan Dispatcher Phalcon membantu kita mendapatkan lebih banyak dari layanan yang disediakan oleh framework.

Dispatch loop 

Ini adalah proses penting yang memiliki banyak kaitan dengan aliran MVC itu sendiri, terutama dengan bagian controller. Pekerjaan dilakukan dalam controller dispatcher. File-file controller dibaca, dimuat, dan dibuat instance. Kemudian action yang diperlukan dieksekusi. Jika action meneruskan aliran ke controller/action lain, controller dispatcher dimulai lagi. Untuk lebih menggambarkan hal ini, contoh berikut menunjukkan proses yang dilakukan dalam Phalcon \ MVC \ Dispatcher :

<?php

//Dispatch loop
while (!$finished) {

    $finished = true;

    $controllerClass = $controllerName . "Controller";

    //Instantiating the controller class via autoloaders
    $controller = new $controllerClass();

    // Execute the action
    call_user_func_array(array($controller, $actionName . "Action"), $params);

    // '$finished' should be reloaded to check if the flow
    // was forwarded to another controller
    $finished = true;
}

Kode di atas tidak memiliki validasi, filter dan pemeriksaan tambahan, tetapi hal ini menunjukkan aliran normal operasi di dispatcher.

Event pada Dispatch Loop  

Phalcon \ MVC \ Dispatcher dapat mengirim event ke EventsManager jika ada. Event yang dipicu menggunakan jenis “dispatch”. Beberapa event ketika mengembalikan boolean false bisa menghentikan operasi aktif. Event berikut ini didukung:

Nama Acara Dipicu Bisa menghentikan operasi? Dipicu pada
beforeDispatchLoop Dipicu sebelum masuk dalam lingkaran pengiriman. Pada titik ini dispatcher tidak tahu apakah controller atau action yang akan dijalankan ada. The Dispatcher hanya mengetahui informasi yang dilewatkan oleh Router. Ya Listeners
beforeDispatch Dipicu setelah masuk dalam lingkaran pengiriman. Pada titik ini dispatcher tidak tahu apakah controller atau action yang akan dijalankan ada. Dispatcher hanya mengetahui informasi yang dilewatkan oleh Router. Ya Listeners
beforeExecuteRoute Dipicu sebelum melaksanakan metode controller / action. Pada titik ini operator telah diinisialisasi controller dan tahu apakah tindakan ada. Ya Listeners / Controllers
initialize Membantu menginisialisasi secara global  controller dalam request Tidak Controllers
afterExecuteRoute Dipicu setelah melaksanakan metode controller / action. Sebagaimana operasi tidak dapat dihentikan, hanya menggunakan event ini untuk membuat pembersihan setelah melaksanakan action Tidak Listeners / Controllers
beforeNotFoundAction Dipicu ketika tindakan tidak ditemukan di controller Ya Listeners
beforeException Dipicu sebelum Dispatcher melempar pengecualian Ya Listeners
afterDispatch Dipicu setelah melaksanakan metode controller / action. Sebagaimana operasi tidak dapat dihentikan, hanya menggunakan event ini untuk membuat pembersihan setelah melaksanakan action Ya Listeners
afterDispatchLoop Dipicu setelah keluar dari loop dispatch Tidak Listeners

tutorial invo  menunjukkan bagaimana untuk memanfaatkan dari pengiriman event Dispatcher untuk menerapkan filter keamanan dengan Acl

Contoh berikut menunjukkan bagaimana untuk melampirkan pendengar untuk komponen ini:

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function(){

    //Create an event manager
    $eventsManager = new EventsManager();

    //Attach a listener for type "dispatch"
    $eventsManager->attach("dispatch", function($event, $dispatcher) {
        //...
    });

    $dispatcher = new MvcDispatcher();

    //Bind the eventsManager to the view component
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;

}, true);

Sebuah instance Controller secara otomatis bertindak sebagai pendengar untuk event dispatcher, sehingga Anda dapat menerapkan metode sebagai callback:

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function beforeExecuteRoute($dispatcher)
    {
        // Executed before every found action
    }

    public function afterExecuteRoute($dispatcher)
    {
        // Executed after every found action
    }

}

Meneruskan ke Action lain 

dispatch loop memungkinkan kita untuk meneruskan aliran eksekusi ke controller/action lain. Hal ini sangat berguna untuk memeriksa apakah pengguna dapat mengakses ke opsi tertentu, redirect pengguna ke tampilan lain atau hanya menggunakan kembali beberapa kode.

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function saveAction($year, $postTitle)
    {

        // .. store some product and forward the user

        // Forward flow to the index action
        $this->dispatcher->forward(array(
            "controller" => "post",
            "action" => "index"
        ));
    }

}

Perlu diingat bahwa “forward” tidak sama dengan membuat redirect HTTP. Meskipun memberikan hasil yang sama. “forward” tidak mereload halaman saat ini, semua pengalihan terjadi dalam satu permintaan, sedangkan redirect HTTP membutuhkan dua permintaan untuk menyelesaikan proses.

contoh lain forwarding:

<?php

// Forward flow to another action in the current controller
$this->dispatcher->forward(array(
    "action" => "search"
));

// Forward flow to another action in the current controller
// passing parameters
$this->dispatcher->forward(array(
    "action" => "search",
    "params" => array(1, 2, 3)
));

Perintah forward menerima parameter berikut:

Parameter Dipicu
controller Sebuah nama kontroler yang valid untuk forward.
action Sebuah nama tindakan yang sah untuk forward.
params Array parameter untuk action
namespace Sebuah nama namespace yang valid di mana kontroler berada

Mempersiapkan Parameter 

Berkat hook poin yang disediakan oleh Phalcon \ MVC \ Dispatcher Anda dapat dengan mudah mengadaptasikan aplikasi untuk setiap skema URL:

Misalnya, Anda ingin URL terlihat seperti: http://example.com/controller/key1/value1/key2/value

Parameter secara default dikirimkan sebagai adanya dalam URL untuk action, Anda dapat mengubahnya ke skema yang diinginkan:

<?php

use Phalcon\Dispatcher,
    Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Attach a listener
    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {

        $keyParams = array();
        $params = $dispatcher->getParams();

        //Use odd parameters as keys and even as values
        foreach ($params as $number => $value) {
            if ($number & 1) {
                $keyParams[$params[$number - 1]] = $value;
            }
        }

        //Override parameters
        $dispatcher->setParams($keyParams);
    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

Jika skema yang diinginkan adalah: http://example.com/controller/key1:value1/key2:value , kode berikut yg diperlukan:

<?php

use Phalcon\Dispatcher,
    Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Attach a listener
    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {

        $keyParams = array();
        $params = $dispatcher->getParams();

        //Explode each parameter as key,value pairs
        foreach ($params as $number => $value) {
            $parts = explode(':', $value);
            $keyParams[$parts[0]] = $parts[1];
        }

        //Override parameters
        $dispatcher->setParams($keyParams);
    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

Mendapatkan Parameter 

Ketika rute memberikan parameter dgn nama Anda dapat menerimanya dalam controller, view atau komponen lain yang extend dr Phalcon \ DI \ Injectable .

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function saveAction()
    {

        // Get the post's title passed in the URL as parameter
        // or prepared in an event
        $title = $this->dispatcher->getParam("title");

        // Get the post's year passed in the URL as parameter
        // or prepared in an event also filtering it
        $year = $this->dispatcher->getParam("year", "int");
    }

}

Mempersiapkan Action 

Anda juga dapat menentukan skema bebas atas action sebelum dispatch.

Nama action Camelize 

Jika URL asli adalah: http://example.com/admin/products/show-latest-products , dan misalnya Anda ingin camelize ‘show-terbaru-produk’ to ‘ShowLatestProducts’, kode berikut diperlukan:

<?php

use Phalcon\Text,
    Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Camelize actions
    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {
        $dispatcher->setActionName(Text::camelize($dispatcher->getActionName()));
    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

Hapus ekstensi warisan 

Jika URL asli selalu berisi ekstensi ‘.php’:

http://example.com/admin/products/show-latest-products.php

http://example.com/admin/products/index.php

Anda dapat menghapusnya sebelum dispatch ke kombinasi controller / action:

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Remove extension before dispatch
    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {

        //Remove extension
        $action = preg_replace('/\.php$/', '', $dispatcher->getActionName());

        //Override action
        $dispatcher->setActionName($action);
    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

Inject instance Model 

Dalam contoh ini, pengembang ingin memeriksa parameter bahwa suatu action akan diterima sesuai perintah untuk secara dinamis menyuntikkan instance model.

Controller tampak seperti:

<?php

class PostsController extends \Phalcon\Mvc\Controller
{
    /**
     * Shows posts
     *
     * @param \Posts $post
     */
    public function showAction(Posts $post)
    {
        $this->view->post = $post;
    }
}

Metode ‘showAction’ menerima sebuah instance dari model Posts, pengembang bisa memeriksanya sebelum dispatch ke action mempersiapkan parameter yang sesuai:

<?php

use Phalcon\Text,
    Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    $eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {

        //Possible controller class name
        $controllerName =   Text::camelize($dispatcher->getControllerName()) . 'Controller';

        //Possible method name
        $actionName = $dispatcher->getActionName() . 'Action';

        try {

            //Get the reflection for the method to be executed
            $reflection = new \ReflectionMethod($controllerName, $actionName);

            //Check parameters
            foreach ($reflection->getParameters() as $parameter) {

                //Get the expected model name
                $className = $parameter->getClass()->name;

                //Check if the parameter expects a model instance
                if (is_subclass_of($className, 'Phalcon\Mvc\Model')) {

                    $model = $className::findFirstById($dispatcher->getParams()[0]);

                    //Override the parameters by the model instance
                    $dispatcher->setParams(array($model));
                }
            }

        } catch (\Exception $e) {
            //An exception has occurred, maybe the class or action does not exist?
        }

    });

    $dispatcher = new MvcDispatcher();
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

Contoh di atas telah disederhanakan untuk tujuan akademik. Seorang pengembang dapat memperbaikinya untuk menyuntikkan jenis depedency atau model dalam action sebelum dieksekusi.

Penanganan Eksepsi Not-Found 

Menggunakan EventsManager sangat mungkin untuk memasukkan titik kait/hook sebelum dispatcher melempar eksepsi ketika kombinasi controller / action tidak ditemukan:

<?php

use Phalcon\Dispatcher,
    Phalcon\Mvc\Dispatcher as MvcDispatcher,
    Phalcon\Events\Manager as EventsManager,
    Phalcon\Mvc\Dispatcher\Exception as DispatchException;

$di->set('dispatcher', function() {

    //Create an EventsManager
    $eventsManager = new EventsManager();

    //Attach a listener
    $eventsManager->attach("dispatch:beforeException", function($event, $dispatcher, $exception) {

        //Handle 404 exceptions
        if ($exception instanceof DispatchException) {
            $dispatcher->forward(array(
                'controller' => 'index',
                'action' => 'show404'
            ));
            return false;
        }

        //Alternative way, controller or action doesn't exist
        if ($event->getType() == 'beforeException') {
            switch ($exception->getCode()) {
                case \Phalcon\Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
                case \Phalcon\Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
                    $dispatcher->forward(array(
                        'controller' => 'index',
                        'action' => 'show404'
                    ));
                    return false;
            }
        }
    });

    $dispatcher = new \Phalcon\Mvc\Dispatcher();

    //Bind the EventsManager to the dispatcher
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;

}, true);

Tentu saja, metode ini dapat dipindahkan ke kelas Plugin independen, yang memungkinkan lebih dari satu kelas mengambil tindakan ketika sebuah pengecualian diproduksi di loop pengiriman:

<?php

use Phalcon\Mvc\Dispatcher,
    Phalcon\Events\Event,
    Phalcon\Mvc\Dispatcher\Exception as DispatchException;

class ExceptionsPlugin
{
    public function beforeException(Event $event, Dispatcher $dispatcher, $exception)
    {

        //Handle 404 exceptions
        if ($exception instanceof DispatchException) {
            $dispatcher->forward(array(
                'controller' => 'index',
                'action' => 'show404'
            ));
            return false;
        }

        //Handle other exceptions
        $dispatcher->forward(array(
            'controller' => 'index',
            'action' => 'show503'
        ));

        return false;
    }
}

Hanya eksepsi yang dihasilkan oleh dispatcher dan eksepsi yang dihasilkan dalam action tereksekusi akan diberitahukan dalam event ‘beforeException’. Eksepsi yg diproduksi di pendengar atau event kontroler redirect ke try/catch terakhir.

Menerapkan Dispatcher Anda sendiri  

antarmuka Phalcon \ MVC \ DispatcherInterface  harus diimplementasikan untuk menciptakan dispatcher Anda sendiri menggantikan yang disediakan oleh Phalcon.

 

Terjemahan dr Dispatching Controller Phalcon
http://docs.phalconphp.com/en/latest/reference/dispatching.html