Completed
Push — master ( 31e846...f233e3 )
by Askupa
02:37
created

Component_composite::create_component()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Amarkal\UI;
4
5
/**
6
 * Implements a Composite UI component.
7
 */
8
class Component_composite
9
extends AbstractComponent
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
10
implements ValueComponentInterface, 
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
Coding Style introduced by
The first item in a multi-line implements list must be on the line following the implements keyword
Loading history...
11
           DisableableComponentInterface,
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces before interface name; 11 found
Loading history...
12
           FilterableComponentInterface,
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces before interface name; 11 found
Loading history...
13
           ValidatableComponentInterface
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces before interface name; 11 found
Loading history...
14
{
15
    /**
16
     * The list of child components.
17
     * 
18
     * @var UI\AbstractComponent[] 
19
     */
20
    private $components;
21
    
22
    /**
23
     * The __set magic method is overridden here to apply value changes to 
24
     * child components.
25
     */
26
    public function __set( $name, $value )
27
    {
28
        parent::__set($name, $value);
29
        
30
        if( 'value' === $name )
31
        {
32
            $this->set_value($value);
33
        }
34
    }
35
    
36
    /**
37
     * Apply the value to each of the child components.
38
     * 
39
     * @param array $value
40
     */
41
    public function set_value( array $value )
42
    {
43
        foreach($value as $n => $v)
44
        {
45
            $component = $this->get_component($n);
46
            $component->value = $v;
47
        }
48
    }
49
    
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function default_model() 
54
    {
55
        return array(
56
            'name'          => '',
57
            'parent_name'   => '',
58
            'id'            => '',
59
            'disabled'      => false,
60
            'template'      => null,
61
            'components'    => array(),
62
            'filter'        => null,
63
            'validation'    => null
64
        );
65
    }
66
    
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function required_arguments()
71
    {
72
        return array('name','components','template');
73
    }
74
    
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function get_template_path() 
79
    {
80
        return __DIR__.'/template.phtml';
81
    }
82
    
83
    /**
84
     * Parse the template by converting the name tokens into UI components.
85
     * 
86
     * @return string The parsed template
87
     */
88
    public function parse_template()
89
    {
90
        return preg_replace_callback('/\{\{([a-zA-Z\d-_]+)\}\}/', function($a){
91
            $component = $this->get_component($a[1]);
92
            return $component->render();
93
        }, $this->model['template']);
94
    }
95
    
96
    /**
97
     * If this is the root composite component, this will return the component's 
98
     * name. If this is a child composite component, this will return the
99
     * component's name as a key in the parent's array, i.e 'parent_name[child_name]'
100
     * 
101
     * @return string
102
     */
103
    public function get_name()
104
    {
105
        if('' !== $this->parent_name)
0 ignored issues
show
Documentation introduced by
The property parent_name does not exist on object<Amarkal\UI\Component_composite>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
106
        {
107
            return "{$this->parent_name}[{$this->name}]";
0 ignored issues
show
Documentation introduced by
The property parent_name does not exist on object<Amarkal\UI\Component_composite>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property name does not exist on object<Amarkal\UI\Component_composite>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
108
        }
109
        return $this->name;
0 ignored issues
show
Documentation introduced by
The property name does not exist on object<Amarkal\UI\Component_composite>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
110
    }
111
    
112
    /**
113
     * Instantiate child UI components when created.
114
     */
115
    protected function on_created()
116
    {
117
        foreach( $this->model['components'] as $args )
118
        {
119
            $this->components[$args['name']] = $this->create_component($args);
120
        }
121
    }
122
    
123
    /**
124
     * 
125
     * @param type $args
126
     * @return type
127
     */
128
    private function create_component( $args )
129
    {
130
        $type = $args['type'];
131
        
132
        if('composite' === $type)
133
        {
134
            $args['parent_name'] = $this->get_name();
135
        }
136
        
137
        $c = \Amarkal\UI\ComponentFactory::create( $type, $args );
138
        
139
        // Apply the composite name template
140
        $c->name_template = str_replace('{{parent_name}}', $this->get_name(), $c->composite_name_template);
141
        
142
        return $c;
143
    }
144
    
145
    /**
146
     * Get a child component by name.
147
     * 
148
     * @param string $name
149
     * @return UI\AbstractComponent
150
     * @throws \RuntimeException If there's no child component corresponding to the given name
151
     */
152
    private function get_component( $name )
153
    {
154
        if(!array_key_exists($name, $this->components))
155
        {
156
            throw new \RuntimeException("Composite sub-component not found with name $name");
157
        }
158
        return $this->components[$name];
159
    }
160
}