Completed
Push — master ( f1bf6d...4a73dc )
by Antarès
02:57
created

AutoMethodsTrait   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 86.11%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 20
c 2
b 0
f 1
lcom 1
cbo 1
dl 0
loc 137
ccs 62
cts 72
cp 0.8611
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
C __call() 0 75 15
B getMethodCallInfo() 0 31 5
1
<?php
2
3
namespace Accessible;
4
5
use \Accessible\MethodManager\MethodCallManager;
6
use \Accessible\MethodManager\ListManager;
7
use \Accessible\MethodManager\MapManager;
8
use \Accessible\MethodManager\SetManager;
9
10
trait AutoMethodsTrait
11
{
12
    /**
13
     * This function will be called each time a getter or a setter that is not
14
     * already defined in the class is called.
15
     *
16
     * @param  string $name The name of the called function.
17
     *                      It must be a getter or a setter.
18
     * @param  array  $args The array of arguments for the called function.
19
     *                      It should be empty for a getter call,
20
     *                      and should have one item for a setter call.
21
     *
22
     * @return mixed    The value that should be returned by the function called if it is a getter,
23
     *                  the object itself if the function called is a setter.
24
     *
25
     * @throws \BadMethodCallException      When the method called is neither a getter nor a setter,
26
     *         						   		or if the access right has not be given for this method,
27
     *         						     	or if the method is a setter called without argument.
28
     * @throws \InvalidArgumentException    When the argument given to the method called (as a setter)
29
     *         								does not satisfy the constraints attached to the property
30
     *         								to modify.
31
     */
32 31
    public function __call($name, array $args)
33
    {
34 31
        $this->getPropertiesInfo();
0 ignored issues
show
Documentation Bug introduced by
The method getPropertiesInfo does not exist on object<Accessible\AutoMethodsTrait>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
35
36 31
        $methodCallInfo = $this->getMethodCallInfo($name);
37 28
        $method = $methodCallInfo['method'];
38 28
        $property = $methodCallInfo['property'];
39 28
        $collectionProperties = $methodCallInfo['collectionProperties'];
40
41 28
        $valuesToUpdate = array();
42
43
        switch ($method) {
44 28
            case 'get':
45 28
            case 'is':
46 22
                MethodCallManager::assertArgsNumber(0, $args);
47 21
                return $this->$property;
48
49 24
            case 'set':
50 17
                MethodCallManager::assertArgsNumber(1, $args);
51
                // we set a collection here if there is an association with it
52
                if (
53 16
                    !empty($this->_collectionsItemNames['byProperty'][$property])
54 16
                    && !(empty($this->_associationsList[$property]))
0 ignored issues
show
Bug introduced by
The property _associationsList does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
55 16
                ) {
56
                    $itemName = $this->_collectionsItemNames['byProperty'][$property]['itemName'];
57
                    $propertyAddMethod = 'add' . strtoupper(substr($itemName, 0, 1)) . substr($itemName, 1);
58
                    $propertyRemoveMethod = 'remove' . strtoupper(substr($itemName, 0, 1)) . substr($itemName, 1);
59
60
                    foreach ($this->$property as $item) {
61
                        $this->$propertyRemoveMethod($item);
62
                    }
63
                    foreach ($args[0] as $item) {
64
                        $this->$propertyAddMethod($item);
65
                    }
66
                }
67
                // we set a regular property here
68
                else {
69 16
                    $oldValue = $this->$property;
70 16
                    $newValue = $args[0];
71
                    $valuesToUpdate = array(
72 16
                        'oldValue' => $oldValue,
73
                        'newValue' => $newValue
74 16
                    );
75
                    // check that the setter argument respects the property constraints
76 16
                    $this->assertPropertyValue($property, $newValue);
0 ignored issues
show
Documentation Bug introduced by
The method assertPropertyValue does not exist on object<Accessible\AutoMethodsTrait>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
77 13
                    $this->$property = $newValue;
78
                }
79 13
                break;
80
81 11
            case 'add':
82 11
            case 'remove':
83 11
                $valueToUpdate = ($method === 'add') ? 'newValue' : 'oldValue';
84 11
                switch ($collectionProperties['behavior']) {
85 11
                    case 'list':
86 4
                        ListManager::$method($this->$property, $args);
87 4
                        $valuesToUpdate[$valueToUpdate] = $args[0];
88 4
                        break;
89 7
                    case 'map':
90 3
                        MapManager::$method($this->$property, $args);
91 2
                        break;
92 4
                    case 'set':
93 4
                        SetManager::$method($this->$property, $args);
94 4
                        $valuesToUpdate[$valueToUpdate] = $args[0];
95 4
                        break;
96 10
                }
97 10
                break;
98
        }
99
100
        // manage associations
101 19
        if (in_array($method, array('set', 'add', 'remove'))) {
102 19
            $this->updatePropertyAssociation($property, $valuesToUpdate);
0 ignored issues
show
Documentation Bug introduced by
The method updatePropertyAssociation does not exist on object<Accessible\AutoMethodsTrait>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
103 19
        }
104
105 19
        return $this;
106
    }
107
108
    /**
109
     * Extract the info about the method called.
110
     *
111
     * @param string $name
112
     *
113
     * @return array
114
     */
115 31
    private function getMethodCallInfo($name)
116
    {
117
        // check that the called method is a valid method name
118
        // also get the call type and the property to access
119 31
        $callIsValid = preg_match("/(set|get|is|add|remove)([A-Z].*)/", $name, $pregMatches);
120 31
        if (!$callIsValid) {
121 1
            throw new \BadMethodCallException("Method $name does not exist.");
122
        }
123
124 30
        $method = $pregMatches[1];
125 30
        $property = strtolower(substr($pregMatches[2], 0, 1)) . substr($pregMatches[2], 1);
126 30
        $collectionProperties = null;
127 30
        if (in_array($method, array('add', 'remove'))) {
128 11
            $collectionProperties = $this->_collectionsItemNames['byItemName'][$property];
129 11
            $property = $collectionProperties['property'];
130 11
        }
131
132
        // check that the method is accepted by the targeted property
133
        if (
134 30
            empty($this->_accessProperties[$property])
0 ignored issues
show
Bug introduced by
The property _accessProperties does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
135 28
            || !in_array($method, $this->_accessProperties[$property])
136 30
        ) {
137 2
            throw new \BadMethodCallException("Method $name does not exist.");
138
        }
139
140
        return array(
141 28
            'method' => $method,
142 28
            'property' => $property,
143
            'collectionProperties' => $collectionProperties
144 28
        );
145
    }
146
}
147