{% extends '../../base.html.twig' %}

{% block body %}
  <div class="container-fluid">
    <div class="row flex-xl-nowrap">
      {% include '../../../documentation/navbar.html.twig' with {
        'route' : nodefony.route
      } %}
      <main class="col-12 col-md-9 col-xl-8 py-md-3 pl-md-5" style="top: 5rem;">

        <div class="page-header">
          <h1><strong>{{ "containerServices" | trans() }} </strong> </h1>
          <p>
          The services container is an entity that can regitrer services and parameters .<br>
          its main interest is to have access to these resources from all over the code.<br>

          </p>

          <p>
          <center>
          <img src="/documentation-bundle/images/container.png" />
          </center>
          </p>
          <p>
          Services Container also manages scopes .</br>
          The notion of scope is a word recuperated from symfony2 . (deprecated in symfony3)</br>
          It can not be the right word (scope) in nodefony ! </br>
          In Nodefony a scope is a clone of container itself that you can change without alter this one</br>
          </p>

          <div class="alert alert-warning">
          Nodefony don't manage container like symfony2 framework but is inspired  <br>
          </div>

        </div>

        <h2 > You can see here :</h2>

        <p>
          <ul>
          <li> <a href="#container"> Container</a></li>
          <li> <a href="#scope"> Scope Container </a></li>
          <li> <a href="#usage"> Nodefony Usage</a></li>

          </ul>
        <p>

        <h2  id="container" >Create Container :</h2>

        <div class="doc3">
          <p>
          </p>

          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer  = new nodefony.Container() ;

        // YOU CAN REGISTER INSTANCE HERSELF HAS SERVICES
        globalContainer.set("global", globalContainer);

        console.log( globalContainer) ;

        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: 'L-uRMqnd-',
          scope: {},
          services: protoService {},
          parameters: protoParameters {}
        }
        */
          </code></pre>

          <div class="alert alert-info">
          <p>
          IN NODEFONY FRAMEWORK  :<br>
          The kernel  instanciate a <strong>global container </strong> who manage all services in application.<br>
          The <strong>Kernel </strong>  is declared as a service in <strong>global container </strong> .<br>
          The <strong>global container </strong> itself is declared as a service by the kernel .<br>
          </p>
          </div>

        </div>


        <h3> Getter and Setter Service in Container </h3>
          <div class="doc3">
          <p>
          You can define an entity as service with <strong>set</strong> method of container (or scope)<br>
          <strong>It is important to add as a service only instance of class</strong></br>

          Example to set as a service  : <br>
          The container core have <strong>set</strong> method to register as service
          </p>


          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer  = new nodefony.Container() ;

        // CREATE CLASSS TO ADD
        const myClass = class myClass {
          constructor() {
            this.settings = {
              foo: "bar"
            };
          }

          getConfig() {
            return this.settings;
          }

        };

        // SET INSTANCE AS SERVICE TO CONTAINER
        globalContainer.set("myService", new myClass());


        // GET SERVICE
        let service = globalContainer.get("myService");

        // USE
        let config = service.getConfig();
        console.log(config)
        // { foo: 'bar' }
          </code></pre>


          <div class="alert alert-info">

          <p>
          IN NODEFONY FRAMEWORK  : <br>
          Nodefony Kernel create an instance of container who registre all services existing in config (Global container). </br>
          The injection service read config file <code>service.xml</code> to add services in container
          </p>
          </div>

          </div>

        <h3> Getter and Setter Parameters in Container </h3>
          <div class="doc3">
          <p>
          </p>

          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer = new nodefony.Container();

        // SET PARAMATERS IN CONTAINER
        let myObject = {
          foo:"bar",
          bar:"foo"
        }
        globalContainer.setParameters( "config", myObject );

        // GET PARAMETERS
        let config = globalContainer.getParameters("config");
        console.log(config);

        //{ foo: 'bar', bar: 'foo' }

        // GET PARAMETERS AS TREE
        let foo = globalContainer.getParameters("config.foo");
        console.log(foo)

        // bar
          </code></pre>
          </div>


        <h2  id="scope">Scope :</h2>

        <div class="doc2">
          <p>
          The scope of the container is a clever clone that allows you to add services without changing its parent container.</br>
          Also the scope inherits all the changes of the parent .  </br>
          You can use scope like container (set , get ...) a scope is a container .
          </p>

          <h3> Create Scope </h3>
          <div class="doc3">
          <p>
          </p>

          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer = new nodefony.Container();

        // CREATE SCOPE WITH NAME
        globalContainer.addScope("request");

        // enterScope CLONE  ;
        let scope = globalContainer.enterScope("request");

        // now varaible scope is a clone of globalContainer

        console.log( scope ) ;
        /*
        Scope {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: '1ojktuxzeD',
          scope: { request: { '1ojktuxzeD': [Circular] } },
          services: protoService {},
          parameters: protoParameters {},
          name: 'request',
          parent:
           Container {
             protoService: [Function: protoService],
             protoParameters: [Function: protoParameters],
             id: 'H4fKie8Dg',
             scope: { request: [Object] },
             services: protoService {},
             parameters: protoParameters {}
          }
        }
        */
        console.log( globalContainer ) ;
        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: 'H4fKie8Dg',
          scope: { request: { '1ojktuxzeD': [Scope] } },
          services: protoService {},
          parameters: protoParameters {}
        }
        */

          </code></pre>
          <div class="alert alert-info" >
          IN NODEFONY FRAMEWORK  : <br>
          HttpKernel create a scope of  kernel container  (scope named : request )  and clone container on each request . </br>
          </div>

          </div>

          <h3> Leave Scope </h3>
          <div class="doc3">
          <p>
          </p>

          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer = new nodefony.Container();

        // CREATE SCOPE WITH NAME
        globalContainer.addScope("request");

        // enterScope CLONE1  ;
        let scope1 = globalContainer.enterScope("request");

        // enterScope CLONE2
        let scope2 = globalContainer.enterScope("request");

        console.log( globalContainer )
        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: '3JCOFJ1-S',
          scope: { request: { eot34LdiAt: [Scope], DWKw457OzD: [Scope] } },
          services: protoService {},
          parameters: protoParameters {}
        }
        */

        // to  detach scope1 to  container
        globalContainer.leaveScope(scope1) ;

        console.log( globalContainer )
        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: '3JCOFJ1-S',
          scope: { request: { DWKw457OzD: [Scope] } },
          services: protoService {},
          parameters: protoParameters {}
        }
        */

        // to  detach scope2 to  container
        globalContainer.leaveScope(scope2) ;

        console.log( globalContainer );
        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: '3JCOFJ1-S',
          scope: { request: {} },
          services: protoService {},
          parameters: protoParameters {}
        }
        */
        // Now you can enterScope (clone) without call  addScope method
          </code></pre>

          </div>


          <h3> Remove Scope </h3>
          <div class="doc3">
          <p>
          </p>

          <pre><code class="hljs javascript" >#!/usr/bin/env node

        const nodefony = require("nodefony");

        // CREATE INSTANCE OF CONTAINER
        const globalContainer = new nodefony.Container();

        // CREATE SCOPE WITH NAME
        globalContainer.addScope("request");

        // enterScope CLONE1  ;
        let scope1 = globalContainer.enterScope("request");

        // enterScope CLONE2
        let scope2 = globalContainer.enterScope("request");

        console.log( globalContainer )

        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: 'cMQEoM6jA',
          scope: { request: { CjELdwMbx2: [Scope], xDw3T85Tr4: [Scope] } },
          services: protoService {},
          parameters: protoParameters {} }
        */

        // to  remove all scopes  to  container and delete
        globalContainer.removeScope("request");

        console.log( globalContainer )
        /*
        Container {
          protoService: [Function: protoService],
          protoParameters: [Function: protoParameters],
          id: 'cMQEoM6jA',
          scope: {},
          services: protoService {},
          parameters: protoParameters {}
        }
        */
        // now who must call addScope method to enterScope
          </code></pre>

          </div>


        </div>

        <h2  id="usage">Nodefony Framewok Usage  :</h2>

        <div class="doc2">
          <p>
          </p>



          <h3 name="" id="">Get service in  <strong>controller</strong>:</h3>

          <div class="doc3">
          <p>
          To use service you must pass by Services Container  :<br>
          Example to use service in action controller : <br>
          The controller core have <strong>get</strong> method to find a service
          </p>

          <pre><code class="hljs javascript" >footerAction (){
          // get kernel service
          let kernel = this.get("kernel");
          const version =  kernel.settings.system.version ;

          // get translation  service
          let translateService = this.get("translation");
          let langs = translateService.getLangs();
          let locale = translateService.getLocale();

          ...
        }
          </code></pre>
          </div>

          <h3 name="" id="">Get Parameters in <strong>controller</strong>:</h3>

          <div class="doc3">
          <p>

          Example to get parameters in controller  : <br>
          The container core have <strong>getParamaters</strong> method to get paramaters
          </p>

          <pre><code class="hljs javascript" >formAction (){

          // get bundle settings ( Paramaters inherits from global container  )
          this.httpSettings = <strong> this.getParameters</strong>("bundles.http");


          // get FORM DATA ( Paramaters added by scope (request)    )
          let query = <strong>this.getParameters</strong>("query");

          ...
        }
          </code></pre>
          <div class="alert alert-info">
          Warnning setter in  controller : <br>
          IN Controller the container is a scope ( request ) . The method <strong>set</strong> and  <strong>setParameters</strong> don't alter the  Global Container.<br>
          This scope have the lifetime of one request .  <br>
          If you set service or parameters in scope,  the container parent is not affected !!! <br>
          </div>

          </div>

        </div>


      </main>
    </div>
  </div>
{% endblock %}
