Cygnite - A Modern Toolkit For Web Developers

The Elegant Way of Building Full-Featured Web Applications

Cygnite Dynamic Routing

Welcome To Cygnite PHP Framework

Showing posts with label Service Container. Show all posts
Showing posts with label Service Container. Show all posts

Service Providers


Documentation


Service Providers

Introduction

Modern PHP application are full of objects. Service is an object of system, which can be defined. A Service is object pool which perform some sort of global task. Cygnite container allow you to standardize and centralize the way objects are constructed into your application. Container makes your life easier, helps you for super fast development, creating standard architecture for reusable and decoupled code base. Service providers are the central place to configure your application, used throughout your application whenever you need to do some specific task Service Provider provides it. When Cygnite bootstrapping all Service Providers are registered and bind into Container.

Using Service Providers allow you to customize objects of own or any third party packages. Providers are dependent on the Cygnite IoC container to resolve objects. It makes writing good code so easy.

Registering Service Provider in the Container

If you open src/Apps/Configs/services.php shipped with cygnite you will find the closure callback where you need to register your Service Provider into array. All service provider classes will be auto loaded for your application.

In this chapter you will be comfortable creating your own ServiceProviderand register them into Cygnite application.


  // Register all service providers here
  
  //Add multiple Service Provider into the array stack     
  $app->registerServiceProvider([
       "\Apps\Services\Payment\ApiServiceProvider",
  ]);


You can add multiple service provider into the array.

Creating Service Provider

All service providers extend the Cygnite\Container\Service\ServiceProvider class. Service provider require register() method on your provider. Register method is only to bind service into the container, so that service will be accessible globally in your application.

Now, let us have a look at sample service provider.



  namespace Apps\Services\Payment;

  use Cygnite\Container\Service\ServiceProvider;
  use Cygnite\Foundation\Application;
  use Apps\Services\PayPal;

  class PaypalServiceProvider extends ServiceProvider
  {
      protected $container;
 
      public function register(Application $app)
      {
            $app['payment.paypal'] = $app->share (function($c) {
                
                return new PayPal($c['paypal.config'], $c['database.default.connection']);
            });
      }
  }


In this above example you can see we have registered "PayPal" service into container.

Getting Service From Container In Controller

Once your service registered using Service Provider you can access service in your controller as such:



 function indexAction() 
 {
     $app = $this->getContainer(); // Or Application::instance();

     show($app['payment.paypal']($app)->get());
 }


How to Define Controllers as Services

Service controller is just a simple class. Cygnite also make use of it's ioc container to resolve 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 and retrieve it from your container in another controller. You can define configuration in the src/Apps/Configs/services.php file as below.


   $app->setServiceController('hello.controller', '\Apps\Controllers\HelloController');

   Or

  // Manually configure Controller instance
  $app->getContainer()->set('hello.controller', function () use ($app)
  {
      return new \Apps\Controllers\HelloController(
                new \Cygnite\Mvc\Controller\ServiceController, $app->getContainer()
      );
  });

Read more about service controller in controller's documentation. That's all about service provider.

IoC Container

Documentation

IoC Container


Introduction

Cygnite has powerful dependency injection container to resolve your class dependencies at runtime. Dependency injection is a software design pattern that implements inversion of control IoC). Cygnite IoC Container gives you more flexibility to write powerful, decoupled and large application.

Usage of Container

Dependency Injection

Cygnite Container can resolve dependencies different ways.

1. Autowiring (Automatic Resolution). Constructor Injection.
2. Interface Injection. Binding an Interface with it's implementation class.
3. Property Injection.

Autowiring

Cygnite container has powerful mechanism to resolve all dependencies of the class at run time without any configuration. Container uses PHP Reflection to understand what parameters a constructor needs. Automatic resolution works only with the constructor injection and must be type-hint.
For Example:

 
namespace Apps\Resources\Extensions;

class Foo 
{
    private $bar;

    public function __construct(\Apps\Resources\Extensions\Bar $bar) 
    {
        $this->bar = $bar;
    }
}


Now make the foo instance using application in your controller.


namespace Apps\Controllers;

use Cygnite\Mvc\Controller\AbstractBaseController;

class UserController extends AbstractBaseController
{
   public function __construct() 
   {
       parent::__construct();

       $app = $this->app();
       $this->foo = $app->make('\Apps\Resources\Extensions\Foo');

       //or
       //$this->foo = $app->resolve('apps.resources.extensions.foo');
   }

}

You can see without doing any kind of configuration Container automatically resolves all dependencies of Foo class and injecting Bar class into it.

Type-Hinting Controller

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

 class HomeController extends AbstractBaseController
 {

    private $api;

    public function __construct(Api $api, $type = "service")
    {
       $this->api = $api;
    }

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

    }
 }

Autowiring works only with the class, however if type of the parameter is Interface then you need to configure to inform Container which Interface implementation should be injected.

Interface Injection

Register an Interface with it's implementation class. This can be done using src/Apps/Configs/definitions/configuration.php configuration file as below.


   'register.alias' => [
        'FooInterface' => 'Apps\Resources\Extensions\Foo'
   ]

and your controller may look like following.


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

 class HomeController extends AbstractBaseController
 {

    private $foo;

    public function __construct(FooInterface $foo)
    {
       $this->foo = $foo;
    }
 }

Since you registered FooInterface to it's implementation class. Cygnite container automatically inject it run time.

Property Injection

Some time over uses of constructor injection may be messy, in that case you may use property injection. You need to configure which instance should be injection into what property of your controller. This can be achieve using src/Apps/Configs/definitions/configuration.php file.
For Example.

   
    return [
        'property.definition' =>  [
            'HomeController' => [
                'service' => 'apps.resources.extensions.api',
            ],
            'ProductController' => [
                'foo' => 'apps.resources.extensions.foo',
            ],
         ],
    ];

Above we have set service object into service property of HomeController, now container is aware about which instance to inject into service property.



 use Cygnite\Mvc\Controller\AbstractBaseController;
 use Apps\Resources\Extensions\Foo;

 class HomeController extends AbstractBaseController
 {

    private $foo;

    // Instance of class \Apps\Resources\Extensions\Service inject here
    private $service;

    public function __construct(Foo $foo)
    {
       $this->foo = $foo;
    }

    public function indexAction()
    {
       // access the service object directly to do some task
       $this->service->makePayment();
    }
 }

Defining a Parameters or Values

Set a parameter or value into Container using instance as array.



   use Cygnite\Container\Container;

   $container = new Container();

   // define some parameters as array 
   $container['foo'] = 'Bar';
   $container['foo_bar'] = 'FooBar';

   OR
  //Define parameter as property
  $container->bar = 'bar';
  $container->baz = new Baz;
  

Accessing Session Instance Into Controller



   $container = $this->get('cygnite.common.session-manager.session');


Creating Service

Service is an object of system, which can be defined by anonymous functions. If you are fond of Pimple syntax then you will also love Cygnite container.



   use Apps\Resources\Extensions\FooBar;
   use Apps\Resources\Extensions\Api;  

   $container['foo'] = 'Foobar';
   $container['bar'] = 'baz';

   $container->general = function ($c) {
       return new FooBar($c['foo']);// Allowing you to refer other service or values
   };

   $container->api = function ($c) {
       return new Api($c['bar'], $c->general);// Allowing you to refer other service or values
   };


If you look at the above example we have stored parameters into the container, as well as stored general service (General object) into container. Now when returning Api service we are able to inject General and other parameters into the Api. You may also notice the Closure has access of container instance inside it.

Extending Service

In the above example we have created service, now you may also want to extend it. To do that simply use extend method.
Have a look at the below example.


  $container['bar'] = 'baz';

  $container->api = function ($c) {
       return new Api();// Allowing you to refer other service or values
   };

  $container['apiKey'] = 'xxxxxxx';

  //Setter Injection and property injection
  $container->api = $container->extend('api', function ($api, $c)
  {
      $api->key = $c['apiKey'];// set key to public property
      $api->setBar($c->bar);

      return $api;
  });
 
  $container->api; //Hold your Api service


Sharing an Object

Binding as shared is almost similar to Singleton pattern, where the first time object is created and return same object for all subsequent call.



 $container->apiGateway = $container->share(function ($c)
 {
     return new ApiGateway($c->api);
 });

 $container->apiGateway ; // Holds singleton object


Creating Singleton Instance



$container->singleton('foobar', function ($c) {
    $config = [];
    return new FooBar($config);
});


Above closure will save the singleton instance into container. But if you just pass class name in singleton method it will return you the singleton instance of the class as below example.



 $foo = $container->singleton('\Apps\Foo');


Setting A Value Into Container



 $container->set('foo', 'bar');


Getting A Value From Container



 $foo = $container->get('foo');
 show($foo);


Checking Value Exists In Container



 if ($container->has('foo')) {
    // 
 }


Returning All Stored Keys From Container



 $container->keys();


Store factory of objects into Container

You also can use the power of SplObjectStorage. Simply get the object of container and attach factory of objects into it.



 $stdClass = new StdClass;
 $general = new General;
 $api = new Api;

 $container->attach($general);
 show($container->contains($api));

 $container->detach($general);

 $general[$api] = "hello";

 
 $container->addAll($general);
 echo $container[$general]."\n";





Testimonials

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