Cygnite - A Modern Toolkit For Web Developers

The Elegant Way of Building Full-Featured Web Applications

Cygnite Dynamic Routing

Controllers


Documentation

Introduction

After determining which controller to use for the route request, your controllers are responsible for handling request and producing the appropriate output to the user. Controller class are to organize the logical work instead defining everything in src/Apps/Routing/Routes.php file. Controllers does most of the magic work for you. It also use to retrieve or save data using model class and use a view page to render HTML output. Meaning that controllers are middleware between your model and views.

Configuring Default Controller

You can set a default controller of your application using configuration in the src/Apps/Configs/application.php file.


  return array(
        'default.controller' => 'Home',
        'default.method'     => 'index',
  );

You may change the default controller and action as you need.

Controllers

1. Controllers are typically stored in the src/Apps/Controllers/ directory.

2. Controllers must have namespaces top of controller file and controller name must be prefixed with the "Controller" string.

3. Every Controller must extends the \Cygnite\Mvc\Controller\AbstractBaseController class.

4. Controllers should have constructor and call parent constructor.

5. Every actions of controllers should be prefixed with the string "Action" after action name. Example- indexAction

6. You can import any classes by using use keyword in the controller.

Basic Controllers

Let us create a simple controller which render a view.


    namespace Apps\Controllers;

    use Apps\Models\User;
    use Cygnite\Mvc\View\View;
    use Cygnite\Foundation\Application;
    use Cygnite\Foundation\Http\Response;
    use Cygnite\Mvc\Controller\AbstractBaseController;

    class UserController extends AbstractBaseController
    {
        // Plain PHP layout
        protected $layout = 'layouts.base';

        public function __construct()
        {
            parent::__construct();
        }
       
        /**
        * Display user profile information based on user id.
        *
        * @request-url: http://www.example.com/cygnite/index.php/user/212
        *
        * @param  int  $id
        * @return mixed Response
        */
        public function profileAction($id)
        {
            $user = User::find($id);
            
            // Apps/Views/user/profile.view.php
            $view = View::create('Apps.Views.user.profile', ['user' => $user]);

            return Response::make($view);
        }
    }

You can route to controller action as below.


 $app->router->get('/user/{:id}', function($route, $id) 
 {

     return $route->callController(["User@profile", [$id]]);
 });

Controller Naming Convention And URL

Request Url: http::/www.example.com/cygnite/index.php/user/index

Class Name Url
UserCategoryController userCategory OR user_category
UserCategoryInfoController userCategoryInfo OR user_category_info

Action Name Url
userInfoAction userInfo OR user_info

Url Rewrite

Cygnite Framework shipped with .htaccess to remove index.php from url. If you miss .htaccess in your installation then create one in the project root directory as below.



 Options +FollowSymLinks
 RewriteEngine On
 php_value safe_mode off
    

    
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule ^(.*)$ index.php/$1 [L] 
    

    Order allow,deny
    Allow from all

Having .htaccess in project root allow you to request same action without index.php in the url as below.


    http://www.example.com/cygnite/index.php/home/index
    // to
    http://www.example.com/cygnite/home/index

Namespace & Controllers

Every class must have namespace. All classes are autoloaded using Composer's PSR4 autoloading standard. You can import number of namespace in the controller without worrying about the performance, all classes are lazy loaded.


  namespace Apps\Controllers;

  use Cygnite\FormBuilder\Form;
  use Cygnite\AssetManager\Asset;
  use Cygnite\Validation\Validator;
  use Apps\Models\Product;

RESTful Resource Controllers

Resource controllers makes easier to build RESTful controllers. Resourceful REST controllers respond to various routes by registering single resource route declaration. A resourceful route is a mapping between HTTP verbs and URLs to controller actions. You may wish to create a RESTful resource controller, using "controller:create" command via craft console can quickly create such controller for you. You just need to define a resource route in the src/Apps/Routing/Routes.php file to respond to various routes.

To create a resource controller execute below command.


  php craft controller:create photo --resource

Above command will generate a "PhotoController.php" file in the src/Apps/Controllers/ directory.

Now let us register resourceful route to "PhotoController" controller as below.


  use Cygnite\Foundation\Application;

  $app = Application::instance();

  $app->router->resource('photos', 'photo'); 

This single line of route entry in the src/Apps/Routing/Routes.php file does all magic under the hood. It creates multiple (seven different routes) routes to handle various actions available in photo resource.

Actions Handled By Resourceful Controller

HTTP Verb Path Controller@Action Used For
GET /photos photo@getIndex display a list of all photos
GET /photos/new photo@getNew return an HTML form for creating a new photo.
POST /photos/ photo@postCreate create a new photo.
GET photos/{id} photo@getShow display a specific photo identified by id.
GET photos/{id}/edit photo@getEdit return an HTML form for editing a photo.
PUT|PATCH photos/{id} photo@putUpdate update a specific photo identified by id.
DELETE photos/{id} photo@delete delete a specific photo.

Resource controller actions are prefixed with the HTTP verb name.

Generating Basic/Resource Controllers

Sometime you may wish to create a resource controller. Don't worry! Cygnite CLI can generate a basic or resource controllers with ease. Sounds interesting. Let us see how to generate controller.


   php craft controller:create photo // will generate basic controller

   php craft controller:create photo --resource // will generate resource controller    

For more details read documentation of cygnite console.

Implicit Controller

Cygnite router also allows you to define a single route to handle every action in a controller class. You just need to prefix HTTP verbs before action name and router is intelligent enough to identify what kind of parameter action expects. But you just need to make sure you are using same patterns name mentioned or you may add custom patterns. You need to specify your controller namespace to route to all available actions in controller class.



  namespace Apps\Controllers;

  use Cygnite\Foundation\Application;
  use Cygnite\Mvc\Controller\AbstractBaseController;

/**
 * This file is generated by Cygnite CLI
 * You may alter code to fit your needs
 */

 class UserController extends AbstractBaseController
 {
    protected $layout = 'layouts.base';

    protected $templateEngine = false;





    public function __construct()
    {
        parent::__construct();
    }

    /**
     * List all data of resource.
     *
     * HTTP Verb: GET - user/index
     *
     */
    public function getIndexAction()
    {
        //
        echo "Hi! " . __FUNCTION__;
    }


    /**
     * Creating a resource and save into database.
     *
     * HTTP Verb: POST - user/create
     */
    public function postCreateAction()
    {
        //
        echo "Hi! " . __FUNCTION__;

    }


    /*
     * Update specific resource into database
     *
     * HTTP Verb: PUT - update/12
     * @param  int $id
     */
    public function putUpdateAction($id)
    {
        //
        echo "Hi! $id   " . __FUNCTION__;

    }


    /**
     * Delete specific resource from database
     * 
     * HTTP Verb: Delete - user/23
     *
     * @param  int $id
     */
    public function deleteAction($id)
    {
        //

        echo "Hi! $id   " . __FUNCTION__;
    }

}

Above sample controller class Apps\Controllers\UserController.php shipped with skeleton class. Add a single route for the class as below in your Routes.php file.



  $app->router->controller('\Apps\Controllers\UserController');


Service Controller

A controller also can act as Service which lead you to any services passed to the controller can be modified via the container configuration. Another advantage of using Controller as service is you can easily decouple code, inject any dependency via constructor, method, or property. You can do some specific task into your service controller, retrieve the controller object from container and perform some tasks. You can define configuration in the src/Apps/Configs/services.php file.


  // Controller as Service
  $app->setServiceController('service.controller', '\Apps\Controllers\HelloController');


Let us consider you want to call Service controller action directly from routes, then call the controller action from routes as below. The defined controller's methods can be called from anywhere using container object.


 $app->router->get('/service/controller', function ($router) {

   $container = $router->getContainer();

   return $container['service.controller']()->indexAction();// Welcome User!
 });


Your Service controller looks like below.



 namespace Apps\Controllers;

 use Cygnite\Mvc\Controller\ServiceController;

 class HelloController
 {
    private $serviceController;
    private $container;

    /**
    * Your constructor.
    * @access public
    */
    public function __construct(ServiceController $serviceController, $container)
    {
        $this->serviceController = $serviceController;
        $this->container = $container;
    }

    /**
    * Default method for your controller. Render index page into browser.
    * @access public
    * @return void
    */
    public function indexAction()
    {
        return "Welcome User!";
    }
 }

Controller Action Events / Hooks

It is quite common in most of the web application development needs some filters or hooks to be executed on the controller actions. It allow you to write some logic to execute right before / after action to be executed. Cygnite makes it easier using request dispatcher.


  namespace Apps\Controllers;

  use Cygnite\Mvc\Controller\AbstractBaseController;

  class HomeController extends AbstractBaseController
  {
    // Plain PHP layout
    protected $layout = 'layout.base';

    public function __construct()
    {
        parent::__construct();
    }

    public function beforeIndexAction()
    {
       // Write your logic. This method will execute before indexAction()
    }

    public function indexAction()
    {
       $content = View::create('Apps.Views.home.welcome', ['title' => 'Welcome to Cygnite Framework']);

       return Response::make($content); 
    }

    public function afterIndexAction()
    {
       // Write your logic. This method will execute after indexAction()
    }
  }


This filters / hooks will get activated only when you specify using direct(static) routes or calling controller from closure callback using $route->callController(["Home@index", [$id]]) method and hooks actions (before, after action) are available in the controller. Route to controller for activating hooks as below.


  $app->router->get('/home/default/', 'Home@index');

Dependency Injection & Controllers

Cygnite controllers are resolved using powerful IoC Container, as a result you are allowed to type-hint any dependencies via constructor. All dependencies are automatically resolved and injected into controller dynamically. For more details have a look on Dependency Injection using IoC Container.

Constructor Injection: Type Hinting

 
 namespace Apps\Controllers;

 use Cygnite\Foundation\Application;
 use Cygnite\Mvc\Controller\AbstractBaseController;
 use Apps\Resources\Extensions\PayPal\Api;

 class HomeController extends AbstractBaseController
 {

    // Api instance 
    protected $paypalApi;

    /**
     * Create a new controller instance.
     *
     * @param  Api  $paypal
     * @return void
     */
    public function __construct(Api $api)
    {
       $this->paypal = $api;
    }

    public function indexAction()
    {
       $this->paypal->makePayment();
    }
 }

Apart from Constructor injection Cygnite's IoC container also provides Interface and Property injection. For more details read documentation of Cygnite IoC Container.

Using HMVC Widgetization: HMVC Request

HMVC modules are great way to separate main controller logic into multiple pieces. The common usages is when use theming or when you want to segregate the whole app into block of sections, where every block of sections does different set of tasks. Likewise you can produce widget output and also can create highly modular application, reusable modules.

You can call modular controller action from your base controller as below.



    // Call src/Apps/Modules/Acme/Controllers/UserController.php indexAction($id)
    $response = $this->call('Acme::User@index', [id' => $id]);


Using Widget Controller

Every HMVC controllers can perform tasks as parent controller. In HMVC module views are represented as widget and rendering widget can be done as follows.


 namespace Apps\Modules\Acme\Controllers;

 use Cygnite\Mvc\View\Widget;
 use Cygnite\Foundation\Application; 
 use Apps\Modules\Acme\Models\User;
 use Cygnite\Mvc\Controller\AbstractBaseController;

 class UserProfileController extends AbstractBaseController
 {

    public function __construct()
    {
        parent::__construct();

    }

   public function indexAction($id)
   {
       $profile = User::findByProfileId($id);

       //Apps/Modules/Acme/Views/user.view.php
       return Widget::make('Acme:user', ['greet' => 'Hello! Widget', 'profile' => $profile], function ($w)
       {
           /*
            | If you pass true for render method Widget
            | will understand you are trying to access module widget
            */
           return $w->render(true);
       });
   }
 }


That's all about the controllers.

Follow Us On Facebook Twitter Google+ Linkedin
Released Under The MIT Public License. Copyrights @2012-2017. Powered by- Sanjoy Dey Productions.