AutoMethodsTrait::getMethodCallInfo()   B
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 5

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 31
ccs 20
cts 20
cp 1
rs 8.439
cc 5
eloc 20
nc 8
nop 1
crap 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 35
    public function __call($name, array $args)
33
    {
34 35
        $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 35
        $methodCallInfo = $this->getMethodCallInfo($name);
37 32
        $method = $methodCallInfo['method'];
38 32
        $property = $methodCallInfo['property'];
39 32
        $collectionProperties = $methodCallInfo['collectionProperties'];
40
41 32
        $valuesToUpdate = array();
42
43
        switch ($method) {
44 32
            case 'get':
45 32
            case 'is':
46 32
            case 'call':
47 25
                MethodCallManager::assertArgsNumber(0, $args);
48 24
                return $this->$property;
49
50 27
            case 'set':
51 18
                MethodCallManager::assertArgsNumber(1, $args);
52
                // we set a collection here if there is an association with it
53
                if (
54 17
                    !empty($this->_collectionsItemNames['byProperty'][$property])
55 17
                    && !(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...
56 17
                ) {
57
                    $itemName = $this->_collectionsItemNames['byProperty'][$property]['itemName'];
58
                    $propertyAddMethod = 'add' . ucfirst($itemName);
59
                    $propertyRemoveMethod = 'remove' . ucfirst($itemName);
60
61
                    foreach ($this->$property as $item) {
62
                        $this->$propertyRemoveMethod($item);
63
                    }
64
                    foreach ($args[0] as $item) {
65
                        $this->$propertyAddMethod($item);
66
                    }
67
                }
68
                // we set a regular property here
69
                else {
70 17
                    $oldValue = $this->$property;
71 17
                    $newValue = $args[0];
72
                    $valuesToUpdate = array(
73 17
                        'oldValue' => $oldValue,
74
                        'newValue' => $newValue
75 17
                    );
76
                    // check that the setter argument respects the property constraints
77 17
                    $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...
78 14
                    $this->$property = $newValue;
79
                }
80 14
                break;
81
82 13
            case 'add':
83 13
            case 'remove':
84 13
                $valueToUpdate = ($method === 'add') ? 'newValue' : 'oldValue';
85 13
                switch ($collectionProperties['behavior']) {
86 13
                    case 'list':
87 6
                        ListManager::$method($this->$property, $args);
88 6
                        $valuesToUpdate[$valueToUpdate] = $args[0];
89 6
                        break;
90 7
                    case 'map':
91 3
                        MapManager::$method($this->$property, $args);
92 2
                        break;
93 4
                    case 'set':
94 4
                        SetManager::$method($this->$property, $args);
95 4
                        $valuesToUpdate[$valueToUpdate] = $args[0];
96 4
                        break;
97 12
                }
98 12
                $this->assertPropertyValue($property, $this->$property);
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...
99 12
                break;
100
        }
101
102
        // manage associations
103 22
        if (in_array($method, array('set', 'add', 'remove'))) {
104 22
            $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...
105 22
        }
106
107 22
        return $this;
108
    }
109
110
    /**
111
     * Extract the info about the method called.
112
     *
113
     * @param string $name
114
     *
115
     * @return array
116
     */
117 35
    private function getMethodCallInfo($name)
118
    {
119 35
        $extractedMethod = preg_match("/^(set|get|is|add|remove)([A-Z].*)/", $name, $pregMatches);
120 35
        if ($extractedMethod) {
121 34
            $method = $pregMatches[1];
122 34
            $property = lcfirst($pregMatches[2]);
123 34
        } else {
124 2
            $method = 'call';
125 2
            $property = $name;
126
        }
127
128 35
        $collectionProperties = null;
129 35
        if (in_array($method, array('add', 'remove'))) {
130 13
            $collectionProperties = $this->_collectionsItemNames['byItemName'][$property];
131 13
            $property = $collectionProperties['property'];
132 13
        }
133
134
        // check that the method is accepted by the targeted property
135
        if (
136 35
            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...
137 32
            || !in_array($method, $this->_accessProperties[$property])
138 35
        ) {
139 3
            throw new \BadMethodCallException("Method $name does not exist.");
140
        }
141
142
        return array(
143 32
            'method' => $method,
144 32
            'property' => $property,
145
            'collectionProperties' => $collectionProperties
146 32
        );
147
    }
148
}
149