Seasar DI Container with AOP
S2Container.PHP5 is a port of Java version Seasar2 to PHP5.
For detailed information about the DIContainer, refer to S2Container.

S2Container Reference

Required Files

Configuration file is required to use S2Container. Configuration file is a specification to build components. Configuration file may be automatically generated by S2 by following S2 programming convention or created manually. Configuration file may be written in XML format and in PHP configuration file format (INI format). File extension of a XML format file may be .dicon or .xml. File extension of a PHP configuration file is .ini. Seasar configuration files are usually written in XML format to be compatible with other versions of Seasar (i.e. Java version and .NET version) and have .dicon extension.

S2Container Definition

S2Container is defined as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="..." class="...">
            ...
    </component>
    <component name="..." class="...">
            ...
    </component>
</components>

DOCTYPE may not be omitted. When creating a dicon file, cut and paste the above sample. Root element is a component. Each component is defined by a component tag and class name is defined in a class attribute of a component tag. Component name is defined in a name attribute of a component. Refer to S2Container Definition Reference for further details.

<components>
    <component name="hoge" class="HogeImpl"/>
</components>

Creating a S2Container

Following methods are used to create a S2Container:

- S2ContainerFactory#create($path)

Argument $path is a path to the configuration file
<?php
$PATH = "path/to/ccc.dicon";
...
$container = S2ContainerFactory::create($PATH);
?>

Getting a Component

Following method is used to get a component from the S2Container:

- S2Container#getComponent($componentKey)

Argument $componentKey is a component class or a component name of component to get. Refer to component Tag for further details. Component class where instanceof class is true may be gotten from the container. The class, however, should be associated with an unique component in the S2Container. If there are several components of the class, TooManyRegistrationRuntimeException is raised because S2Container can not determine which component to get.
Similarly, component name should be unique in the S2Container. Specifying non-unique component name will raise a TooManyRegistrationRuntimeException.

Example: Following defines component named "hoge" of class "Hoge"

<components>
    <component name="hoge" class="Hoge"/>
</components>

Following code gets the component "hoge" by specifying class "Hoge":

<?php
$container = S2ContainerFactory::create($PATH);
$hoge = $container->getComponent('Hoge');
?>

Following code gets the component "hoge" by specifying component name "hoge":

<?php
$container = S2ContainerFactory::create($PATH);
$hoge = $container->getComponent('hoge');
?>

Dependency Injection types

Following is a list of DependencyInjection types:
ConstructorInjection : Use a constructor to set values necessary to construct a component
SetterInjection : Use a setter method to set values necessary to construct a component
MethodInjection : Use initialization method to set values necessary to construct a component
MethodInjection is S2 original DependencyInjection type. All S2 types and their hybrid types are supported.

Constructor Injection

Constructor injection injects dependency through a constructor by using constructor arguments.
It is written in a S2Container configuration file as follows:

  • Component specification
    Component is specified using component tag. Class name is set in class attribute and component name may be set in name attribute.
  • Constructor arguments
    Arguments to a constructor are set in arg elements that are child elements of a component tag.
    When the value of an argument is of type String, it is surrounded by double quotation (").
<components>
    <component name="..." class="...">
          <arg>...</arg>
    </component>
</components>
Refer to example in Constructor injection for details.

Setter Injection

Setter injection injects dependencies (properties) by using setter methods.
It is written in a S2Container configuration file as follows:

  • Component specification
    Component is specified using component tag. Class name is set in class attribute and component name may be set in name attribute.
  • Properties
    Component parameters are set in property elements that are child elements of a component tag.
    Name of a property is specified using name attribute.
<components>
    <component name="..." class="...">
          <property name="...">...</property>
    </component>
</components>
Refer to Setter Injection example for an example.

Method Injection

Method injection injects by invoking an arbitrary method.
It is defined in a S2Container configuration file as follows:
It is written in a S2Container configuration file as follows:

  • Component specification
    Component is specified using component tag. Class name is set in class attribute and component name may be set in name attribute.
  • Initialization method
    Name and argument of method to invoke is set in a initMethod elements that are child elements of a component tag.
    Name of a property is specified using name attribute to this initMethod element. Arguments to the method to invoke is specified as values to arg element which is a child of a initMethod element.
<components>
    <component name="..." class="...">
          <initMethod name="...">
             <arg>...</arg>
          </initMethod>
    </component>
</components>
When there is no argument, name attribute may be omitted and the name of the method may be set by a PHP expression as the value of initMethod element. In this situation, component is represented by $component.
<components>
    <component name="..." class="...">
          <initMethod>...</initMethod>
    </component>
</components>
Refer to Method Injection example for an example.

Dividing and Including S2Container Definition

If all configuration are written in a single file, the file soon becomes very large. S2Container allows developers to divide the configuration file into several files and supports include clause to logically construct one configuration file from these files. Following is an example of including content of bar.dicon file:

<components>
    <include path="bar.dicon"/>
</components>

File to include is specified in the path attribute of a include tag. Refer to include tag for detailed information.
Component are searched in the following order: (1) In the component where the component is registered (2) In child S2Container in order of the include statement.
In the following components definition, "Foo" is searched first, followed by "aaa.dicon" and lastly by "bbb".

<components>
    <include path="aaa.dicon"/>
    <include path="bbb.dicon"/>
    <component class="Foo" />
</components>

When automatically using constructor injection and setter injection, it is possible to automatically inject components in configuration to be included. Refer to automatic binding for conditions to automatically inject dependencies.
Following is an example to show the order of component search. Property of a component to set by setter injection (HelloImpl) is defined in both included configuration files aaa.dicon and bbb.dicon. Let's find out which component HelloClient will use.

root.dicon
<components>
    <include path="aaa.dicon"/>
    <include path="bbb.dicon"/>
    <component name="root" class="RootHelloClient"/>
</components>
aaa.dicon
<components>
    <component class="HelloImpl">
        <property name="message">"Hello Aaa!"</property>
    </component>

    <component name="aaa" class="AaaHelloClient"/>
</components>
bbb.dicon
<components>
    <component class="HelloImpl">
        <property name="message">"Hello Bbb!"</property>
    </component>

    <component name="bbb" class="BbbHelloClient"/>
</components>

Content of each component is as follows:

<?php
interface HelloClient {
    public function showMessage();
}
?>
<?php
class RootHelloClient implements HelloClient {

    private $hello_;

    public function setHello(Hello $hello) {
        $this->hello_ = $hello;
    }

    public function getHello() {
        return $this->hello_;
    }

    public function showMessage() {
        print $this->getHello()->getMessage();
    }
}
?>

Implementation of AaaHelloClient and BbbHelloClient is like those of RootHelloClient.

<?php
interface Hello {
    public function setMessage($helloMessage);
    public function getMessage();
}
?>
<?php
class HelloImpl implements Hello {
    private $helloMessage_;

    public function setMessage($helloMessage) {
        $this->helloMessage_ = $helloMessage;
    }

    public function getMessage() {
        return $this->helloMessage_;
    }
}
?>

HelloImpl only defines Message property. Following are result of invoking showMessage() method in each HelloClient.

Result of RootHelloClient
Hello Aaa!

S2Container will first try to find HelloImpl in root.dicon. Since HelloImpl is not defined in root.dicon, S2Container will next try to find it in the first included file, aaa.dicon. Since HelloImpl is defined in aaa.dicon, this definition is used and "Hello Aaa!" is outputted.

Result of AaaHelloClient
Hello Aaa!

AaaHelloClient used HelloImpl defined in aaa.dicon. When injection is automatically done, child S2Container is unable to use component defined in the parent S2Container. For example, even if HelloImpl is defined in root.dicon, it will not be automatically injected into AaaHelloClient.

Result of BbbHelloClient
Hello Bbb!

Similar to the case with AaaHelloClient, BbbHelloClient uses HelloImpl component defined in bbb.dicon.
Files is this example are available in the s2container.php5/src/examples/dicon/include folder.

Namespace

Namespace is used to distinguish component definitions from several configuration file. Namespace is specified by namespace attribute of a components tag.

foo.dicon
<components namespace="foo">
    <component name="aaa" .../>
    <component name="bbb" ...>
        <arg>aaa</arg>
    </component>
</components>
bar.dicon
<components namespace="bar">
    <include path="foo.dicon"/>
    <component name="aaa" .../>
    <component name="bbb" ...>
        <arg>aaa</arg>
    </component>
    <component name="ccc" ...>
        <arg>foo.aaa</arg>
    </component>
</components>
app.dicon
<components>
    <include path="bar.dicon"/>
</components>

Namespace is not necessary to require to reference components in the same S2Container. To reference components in other S2Container, however, namespace prefix associated with the S2Container is prepended to the component name. For example, foo.aaa and bar.aaa have the same component name "aaa" but have different namespace prefix. Thus, they are treated as two different components.
It is a convention to name the configuration file namespace.dicon.

Instance Management

instance attribute of a component tag specifies how component instance is managed by a S2Container. Default is singleton which implies S2Container#getComponent() method always gets the same component. To get a new component each time S2Container#getComponent() method is invoked, set the instance attribute to prototype. To manage component based on request ($_REQUEST), set the instance attribute to request. To manage based on a session, set the instance attribute to session.

When using Seasar framework with a presentation framework, there may sometimes be a need to set an instance created by a presentation framework to a component managed by S2Container. In this kind of circumstances where Dependency Injection to a component outside the S2Container is necessary, the following method are used.

- S2Container#injectDependency($outerComponent, $componentKey)

Specify external component in the first argument and external component class or component name in the second argument.
Also, set instance attribute to outer in S2Container definition.

instance attribute Description
singleton (default) Same instance is returned on every invocation of S2Container#getComponent()
prototype New instance is returned on each invocation of S2Container#getComponent()
request One instance is created for each request. A component is saved to a request using the name set to the name attribute.
session One instance is created for each session. A component is saved to a session using the name set to the name attribute.
outer Instance of a component is created outside of S2Container. Only dependency is injected. Aspect and Constructor injection can not be applied.

Lifecycle

Using initMethod and destroyMethod, component lifecycle may also be managed by a container. Method specified by initMethod tag is invoked when S2Container is initialized (S2Container#init()) and method specified by destroyMethod tag is invoked when S2Container is destroyed (S2Container#destroy()). initMethod is executed in order as they are defined in the container configuration and destroyMethod is executed in reverse order as they are defined in the container configuration.
When instance attribute is not "singleton", destroyMethod is ignored. Following is an example to set aaa to 111 on initialization and set aa to null termination to HashMap#put method.

<components namespace="bar">
    <component name="map" class="HashMap">
        <initMethod name="put">
            <arg>"aaa"</arg>
            <arg>111</arg>
        </initMethod>
        <destroyMethod name="put">
            <arg>"aaa"</arg>
            <arg>null</arg>
        </destroyMethod>
    </component>
</components>

Automatic Binding

By default, dependency between container is automatically resolved when type is an interface. It is also possible to specify autoBinding attribute in a component tag.

autoBinding Description
auto (default) If an argument to a constructor is explicity specified, that argument is used.
Is an argument is not specified and type is an interface,it is automatically bound.
Default values are set to arguments whose type is not an interface. If default value is not available, an argument is set to null.
If a property is explicitly specified, it is used.
If property is not specified and property type is an interface, it is automatically bound.
constructor If an argument to a constructor is explicitly specified, that argument is used.
Is an argument is not specified and type is an interface,it is automatically bound.
Default values are set to arguments whose type is not an interface. If default value is not available, an argument is set to null.
If a property is explicitly specified, it is used.
property If an argument to a constructor is explicitly specified, that argument is used.
Type interface property is automatically bound.
none If an argument to a constructor is explicitly specified, that argument is used.
If a property is explicitly specified, it is used.

Refer to Automatically binding (constructor injection) and Automatically binding (setter injection) for further details.

Using S2Container from a component

Component should not depend on a S2Container but there are some situations where a component may need to invoke S2Container method. S2Container is defined with a name "container" so is the value of arg or property tag is set to "container" it is possible to get an instance of a container. Furthermore, it is also possible to automatically bind by defining a S2Container type setter method. Following are examples of using arg and property tag to specify "container".

<components>
    <component class="BarImpl">
        <arg>container</arg>
    </component>

    <component class="FooImpl">
        <property name="foo">container</property>
    </component>
</components>

Applying AOP

AOP may be applied to a component. Following is an example of applying TraceInterceptor to a Date class.

<?php
class Date {
    function Date() {}
    
    function getTime(){
        return '12:00:30';
    }
}
?>
<components>
    <component name="traceInterceptor"
               class="TraceInterceptor"/>
    <component class="Date">
        <aspect>traceInterceptor</aspect>
    </component>
</components>

Specify Interceptor name as the value of aspect tag. Method names separated by a comma may be specified in pointcut attribute. When pointcut attribute is not specified, all interfaces implemented by a component is used. Method names may be specified using a regular expression. Following is an example using the above component definition.

<?php
$PATH ="Aop.dicon";
$container = S2ContainerFactory::create($PATH);
$date = $container->getComponent('Date');
$date->getTime();
?>

Following is a sample output from executing the above script.

BEGIN Date#getTime()
END   Date#getTime() : 12:00:30

MetaData

meta data may be applied to components, component, arg, and property tags. meta tag is specified as a child element to the element which is to have a meta tag. Following is an example of specifying a meta tag to a components tag.

<components>
    <meta name="aaa">111</meta>
</components>

Meta data information specified in components, component, arg, and property tags may be retrieved using the following methods defined in S2Container, ComponentDef, ArgDef, and PropertyDef.

  • public function getMetaDefSize()
  • public function getMetaDef($name)

S2Container Definition Reference

DOCTYPE

DOCTYPE is specified right after XML declaration. Following is an example of a component configuration with a DOCTYPE declaration:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="hello" class="HelloConstructorInjection">
        <arg>"Hello World!"</arg>
    </component>
</components>

components tag (required)

Root element

namespace attribute (optional)

Namespace may be specified. Namespace may also be used to differentiate PHP elements.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components namespace="hoge">
    ...
</components>

include tag (optional)

Used to include divided S2Container configuration definitions

path attribute (required)

Specify a path of the configuration file. Must be inserted before a component tag. Full path of a configuration file must be specified. Path may be represented by a constant defined in a PHP by surrounding the constant name with a %.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <include path="path/to/ccc.dicon" />
    <include path="%DICON_DIR%/ddd.dicon" />
</components>

component tag (optional)

Define a component

class attribute (optional)

Specify a class name. If a component is specified using a PHP expression as a value to an element, class attribute may be omitted. If class attribute is specified when PHP expression is used, it will be type checked.

name attribute (optional)

Name may be specified. The name should be choosen so it may be used as a PHP key. Refer to Getting a Component for further details.

instance attribute (optional)

Specify how S2Container manages instance of a component. Possible values are singleton (default), prototype, outer, request, and session. Refer to instance management for further details on these values.

autoBinding attribute (optional)

Specify how S2Container resolves dependencies between components. Possible values are auto (default), constructor, property, and none. Refer to automatic binding for further details on these values.

arg tag (optional)

Used to specify arguments to a constructor when added as an child element to a component element. The order they are specified represents their position in the argument.
When used as a child element to initMethod element or a destroyMethod element, value of an arg element is passes as an argument to the method. The order they are specified represents their position in the argument. A value to be passes as an argument may be written in PHP expression and set as a value of an element or set in a child component element.

property tag (optional)

Used as a child of component element. Value of the property may be written in PHP expression and set to as a value of an element or set in a child component element.

name attribute (optional)

Specify property name.

meta tag (optional)

Used as a child element to components element, component element, arg element, and property element. Value of the meta data may be written in PHP expression and set to as a value of an element or set in a child component element.

name attribute (optional)

Specify meta name.

initMethod tag (optional)

Used as a child element of a component element. Arguments are specified in child arg elements. Method in a component may be invoked without specifying name attribute using PHP expression. $component represents the component defining the initMethod element. $component may be used as an object only within the initMethod element.

name attribute (optional)

Specify method name.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="HashMap">
        <initMethod name="put">
            <arg>"aaa"</arg>
            <arg>111</arg>
        </initMethod>
        <initMethod>$component->put("aaa", 111);</initMethod>
        <initMethod>print "Hello";</initMethod>
    </component>
</components>

destroyMethod tag (optional)

same as initMethod tag

aspect tag (optional)

Weave aspect into a component. Refer to aspect tag for detailed explanation.

description tag (optional)

Description element may be used as a child to components element, component element, arg element, and property element to write a comment.


Examples

S2Container.PHP must be setup before running the following examples.

Constructor Injection

Use constructor injection to display a message. Following files are created in this example:

  • Interface (Hello.class.php)
  • Implementation class (HelloConstructorInjection.class.php)
  • dicon file (HelloConstructorInjection.dicon)
  • Execution script (HelloConstructorInjectionClient.php)
Create interface
  • Define showMessage()

Let's start by defining interfaces. By separating interfaces with their implementation, components only have to be concerned about the interface and not their implementation. Additionally, implementation may be replaced with a mock to make unit testing easier.

<?php
interface Hello {
    public function showMessage();
}
?>
Create implementation class
  • Define a constructor with one argument
  • Implement showMessage()

Next, we'll do implement the interfaces. The constructor of the class will accept a message and output the message using the showMessage() method.

<?php
class HelloConstructorInjection implements Hello {
    private $message;

    public function HelloConstructorInjection($message) {
        $this->message = $message;
    }

    public void showMessage() {
        print $this->message . "\n";
    }
}
?>
Create dicon file
  • Define a component using component tag
  • Set an argument by creating an argelement that is a child element to a component element.

S2Container is responsible for setting the message to a component. Components are created based on the configuration file.

s2container.php5/src/examples/dicon/HelloConstructorInjection.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="hello" class="HelloConstructorInjection">
        <arg>"Hello World!"</arg>
    </component>
</components>
Create execution script

s2container.php5/src/examples/dicon/HelloConstructorInjectionClient.php

<?php
require_once(dirname(__FILE__) . '/example.inc.php');
$PATH =	EXAMPLE_DIR . "/dicon/HelloConstructorInjection.dicon";
		
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('Hello');
$hello->showMessage();
		
$hello2 = $container->getComponent("hello");
$hello2->showMessage();
?>
Result

String value in the arg tag should be displayed as below:

% php HelloConstructorInjectionClient.php
Hello World!
Hello World!
%

Files in this example are available in the s2container.php5/src/examples/dicon folder.

Setter Injection

Display a message using setter injection. Following files are created in this example:

  • Interface (Hello.class.php)
  • Implementation class (HelloSetterInjection.class.php)
  • dicon file (HelloSetterInjection.dicon)
  • Execution script (HelloSetterInjectionClient.php)
Create interface
  • Define showMessage()

Interface is the same as constructor injection. There is no need to define getter method and setter method to a property. This is because whether to use constructor or setter method to inject dependency should be decided by the implementation.

<?php
interface Hello {
    public void showMessage();
}
?>
Create an implementation class
  • Define setter method (setMessage)
  • Implement showMessage()

We'll tackle the implementation next. Message is received by the setter method and outputted by the showMessage() method.

<?php
class HelloSetterInjection implements Hello {
    private $message;

    public function HelloSetterInjection() {
    }

    public function setMessage($message) {
        $this->message = $message;
    }

    public function showMessage() {
        print $this->message . "\n";
    }
}
?>
Create dicon file
  • Define component using component tag
  • Define component property in property element which is a child of a component element.

s2container.php5/src/examples/dicon/HelloSetterInjection.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="HelloSetterInjection">
        <property name="message">"Hello World!"</property>
    </component>
</components>
Create execution script
  • Invoke S2ContainerFactory#create($path) and create S2Container
  • Use getComponent() and get component from the S2Container
  • Invoke on the method in the component from S2Container

s2container.php5/src/examples/dicon/HelloSetterInjectionClient.php

<?php
require_once(dirname(__FILE__) . '/example.inc.php');
$PATH = EXAMPLE_DIR . "/dicon/HelloSetterInjection.dicon";
		
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('Hello');
$hello->showMessage();
?>
Result

String specified in the property tag is displayed as below:

% php HelloSetterInjectionClient.php
Hello World!
%

Files in this example are available in the s2container.php5/src/examples/dicon folder.

Method Injection

Display a message using method injection. Following files are created in this example:

  • Interface (Hello.class.php)
  • Implementation class (HelloMethodInjection.class.php)
  • dicon file (HelloMethodInjection.dicon)
  • Execution script (HelloMethodInjectionClient.php)
Create interface
  • Define showMessage()

In most cases, injected method is called several but in this example, the same interface as the constructor injection example is used.

<?php
interface Hello {
    public function showMessage();
}
?>
Create implementation class
  • Define addMessage()
  • Implement showMessage()

Next, it's implementation. Use addMessage($message) to add messages several times, and display received messages by using showMethod().

<?php
class HelloMethodInjection implements Hello {
    private $buf = "";
	
    public function HelloMethodInjection() {}
	
    public function addMessage($message) {
        $this->buf .= $message;
    }

    public function showMessage() {
        print $this->buf . "\n";
    }
}
?>
Create dicon file
  • Define component using component tag
  • Define arguments for a method in a component in initMethod element which is a child element of a component element.

First, use arg tag to set String "Hello" to ddMessage($message).
Next, use PHP expression to set "World!" to addMessage($message).

s2container.php5/src/examples/dicon/HelloMethodInjection.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="HelloMethodInjection">
        <initMethod name="addMessage">
            <arg>"Hello "</arg>
        </initMethod>
        <initMethod>$component->addMessage("World!")</initMethod>
    </component>
</components>
Create execution script
  • Invoke S2ContainerFactory#create($path) to create S2Container
  • Invoke getComponent() to get a component from the S2Container
  • Invoke the method in the component from S2Container
<?php
require_once(dirname(__FILE__) . '/example.inc.php');
$PATH = EXAMPLE_DIR . "/dicon/HelloMethodInjection.dicon";
		
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('Hello');
$hello->showMessage();
?>
Result

String set as the value to initMethod element should display as below:

% php HelloMethodInjectionClient.php
Hello World!
%

Files in this example are available in the s2container.php5/src/examples/dicon folder.

Automatic binding (constructor injection)

Let's display a message using automatic binding. Following files are created in this example:

  • Interface (Hello.class.php)
  • Implementation class of an interface(AutoHelloConstructorInjection.class.php)
  • Map interface (Map.class.php)
  • Implementation class of a Map interface (HashMap.class.php)
  • dicon file (AutoHelloConstructorInjection.dicon)
  • Execution script (AutoHelloConstructorInjectionClient.php)
Create an interface
  • Define showMessage()
<?php
interface Hello {
    public function showMessage();
}
?>
Create execution script
  • Define construction with argument Map
  • Implement showMessage()

Receive Map from a constructor, use "hello" as a key to showMessage() method to retrieve message from a Map, and output the message.

<?php
class AutoHelloConstructorInjection implements Hello {

    private $messages;
	
    public function AutoHelloConstructorInjection(Map $messages) {
        $this->messages = $messages;
    }
	
    public function showMessage() {
        print $this->messages->get('hello') . "\n";
    }
}
?>
Create Map interface
  • Define put($key,$val)
  • Define get($key)
<?php
interface Map {
    function put($key,$val);
    function get($key);
}
?>
Create implementation class of Map interface
  • Define constructor with argument Map
  • Implement showMessage()
<?php
class HashMap implements Map{
    private $pool = array();
    
    function HashMap() {}
    
    function put($key,$val){
    	$this->pool[$key] = $val;
    }
    
    function get($key){
    	return array_key_exists($key,$this->pool) ? $this->pool[$key] : null;
    }
}
?>
Create dicon file
  • Define HashMap, which is a specified in a component tag as a implementation class of Map, as a component
  • Define a HashMap with key "hello" and value "Hello World!" in a initMethod element which is a child of component element.
  • Define a component AutoHelloConstructorInjection in a component tag. Set autoBinding attribute to "auto".
    We are explicitly setting "auto" to yes but since this is the default value of autoBinding attribute, it is not required.

Notice that the arg tag does not have a definition of AutoHelloConstructorInjection. arg tag definition is required in a constructor injection but if there is a implementation class of a Map in S2Container, S2Container will search the container and set the argument. However, if the argument type is not a interface, that argument is not automatically bound.

s2container.php5/src/examples/dicon/autobinding/AutoHelloConstructorInjection.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="HashMap">
        <initMethod name="put">
            <arg>"hello"</arg>
            <arg>"Hello World!"</arg>
        </initMethod>
    </component>

    <component autoBinding="auto"
               class="AutoHelloConstructorInjection"/>
</components>
Create execution script
<?php
require_once(dirname(dirname(__FILE__)) . '/example.inc.php');
$PATH =	EXAMPLE_DIR . "/dicon/autobinding/AutoHelloConstructorInjection.dicon";
		
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('Hello');
$hello->showMessage();
?>
Result

Value set in the HashMap is display as below showing constructor argument was automatically bound.

% php AutoHelloConstructorInjection.php
Hello World!
%

Files in this example are available in the s2container.php5/src/examples/dicon/autobinding folder.

Automatic binding (setter injection)

Display message using automatic binding. Following files are created in this example:

  • Interface (Hello.class.php)
  • Implementation class of an interface (AutoHelloSetterInjection.class.php)
  • dicon file (AutoHelloSetterInjection.dicon)
  • Execution script (AutoHelloSetterInjectionClient.php)
Create an interface
  • Define showMessage()
<?php
interface Hello {
    public function showMessage();
}
?>
Create execution script
  • Implement showMessage() with argument Map

Retrieve Map from setMessage(Map map) and output the value retrieve value from a Map with key "hello" using showMessage()

<?php
class AutoHelloSetterInjection implements Hello {

    private $messages;
	
    public function AutoHelloSetterInjection() {}
	
    public function setMessage(Map $messages) {
        $this->messages = $messages;
    }

    public function showMessage() {
        print $this->messages->get('hello') . "\n";
    }
}
?>
Create dicon file
  • Define HashMap as a component in a component tag.
  • Define a HashMap with key "hello" and value "Hello World!" in a initMethod element which is a child of component element.
  • Define a component AutoHelloSetterInjection in a component tag. Set autoBinding attribute to "auto".
    We are explicitly setting "auto" to yes but since this is the default value of autoBinding attribute, it is not required.

Notice that the property tag does not have a definition of AutoHelloSetterInjection. property tag definition may be required but if there is a implementation class of a Map in S2Container, S2Container will search the container and set the parameter. However, if the property type is not a interface, that property is not automatically bound.

s2container.php5/src/examples/dicon/autobinding/AutoHelloSetterInjection.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="HashMap">
        <initMethod name="put">
            <arg>"hello"</arg>
            <arg>"Hello World!"</arg>
        </initMethod>
    </component>

    <component autoBinding="auto"
               class="AutoHelloSetterInjection"/>
</components>
Create execution script
<?php
require_once(dirname(dirname(__FILE__)) . '/example.inc.php');
$PATH = EXAMPLE_DIR . "/dicon/autobinding/AutoHelloSetterInjection.dicon";
		
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('Hello');
$hello->showMessage();
?>
Result

Value of HashMap is displayed showing the property was automatically set.

% php AutoHelloSetterInjection.php
Hello World!
%

Files in this example are available in the s2container.php5/src/examples/dicon/autobinding folder.