AutoMethodsTrait::__call()   C
last analyzed

Complexity

Conditions 16
Paths 41

Size

Total Lines 77
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 17.4584

Importance

Changes 5
Bugs 0 Features 3
Metric Value
c 5
b 0
f 3
dl 0
loc 77
ccs 46
cts 56
cp 0.8214
rs 5.1945
cc 16
eloc 54
nc 41
nop 2
crap 17.4584

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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