Test Failed
Push — master ( b391e8...f206d0 )
by vistart
09:32
created

SubsidiaryTrait::addSubsidiaryClass()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8.0368

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 21
ccs 11
cts 12
cp 0.9167
rs 7.1428
cc 8
eloc 15
nc 5
nop 2
crap 8.0368
1
<?php
2
3
/**
4
 *   _   __ __ _____ _____ ___  ____  _____
5
 *  | | / // // ___//_  _//   ||  __||_   _|
6
 *  | |/ // /(__  )  / / / /| || |     | |
7
 *  |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\base\models\traits;
14
15
use yii\base\InvalidConfigException;
16
17
/**
18
 * @version 1.0
19
 * @author vistart <[email protected]>
20
 */
21
trait SubsidiaryTrait
22
{
23
    /**
24
     * @var string[] Subsidiary map.
25
     * Array key represents class alias,
26
     * array value represents the full qualified class name corresponds to the alias.
27
     *
28
     * For example:
29
```php
30
public $subsidiaryMap = [
31
    'Profile' => 'app\models\user\Profile',
32
];
33
```
34
     * Or
35
```php
36
public $subsidiaryMap = [
37
    'Profile' => [
38
        'class' => 'app\models\user\Profile',
39
    ],
40
];
41
```
42
     *
43
     * The other elements will be taken if subsidiary configuration does not specify.
44
     * If you want to create subsidiary model and the class is not found, the array elements will be taken.
45
     */
46
    public $subsidiaryMap = [];
47
    
48
    /**
49
     * Add subsidiary class to map.
50
     * @param string $name
51
     * @param string|array $config
52
     * @return boolean
53
     * @throws InvalidConfigException
54
     */
55 7
    public function addSubsidiaryClass($name, $config)
56
    {
57 7
        if (!is_string($name) || empty($name)) {
58 2
            throw new InvalidConfigException('Subsidiary name not specified.');
59
        }
60 7
        $name = strtolower($name);
61 7
        if (!is_array($config)) {
62 7
            if (is_string($config) && !empty($config)) {
63 7
                $this->subsidiaryMap[$name] = ['class' => $config];
64
            } else {
65
                throw new InvalidConfigException('Subsidiary class not specified.');
66
            }
67
        } else {
68 2
            if (isset($config['class']) && class_exists($config['class'])) {
69 2
                $this->subsidiaryMap[$name] = $config;
70
            } else {
71 1
                throw new InvalidConfigException('Subsidiary class not specified.');
72
            }
73
        }
74 7
        return true;
75
    }
76
    
77
    /**
78
     * Remove subsidiary.
79
     * @param string $name
80
     * @return boolean
81
     */
82 1
    public function removeSubsidiary($name)
83
    {
84 1
        $name = strtolower($name);
85 1
        if (array_key_exists($name, $this->subsidiaryMap)) {
86 1
            unset($this->subsidiaryMap[$name]);
87 1
            return true;
88
        }
89 1
        return false;
90
    }
91
    
92
    /**
93
     * Get subsidiary class.
94
     * @param string $name
95
     * @return string
96
     */
97 7
    public function getSubsidiaryClass($name)
98
    {
99 7
        $name = strtolower($name);
100 7
        if (array_key_exists($name, $this->subsidiaryMap) && array_key_exists('class', $this->subsidiaryMap[$name])) {
101 7
            return class_exists($this->subsidiaryMap[$name]['class']) ? $this->subsidiaryMap[$name]['class'] : null;
102
        }
103 1
        return null;
104
    }
105
    
106 2
    public function getSubsidiaries($name, $limit = 'all', $page = 0)
107
    {
108 2
        $class = $this->getSubsidiaryClass($name);
109 2
        if (empty($class)) {
110 1
            return null;
111
        }
112 2
        $query = $class::find();
113 2
        if (!method_exists($query, 'createdBy')) {
114
            return null;
115
        }
116 2
        return $class::find()->createdBy($this)->page($limit, $page)->all();
117
    }
118
    
119 7
    public function __call($name, $arguments)
120
    {
121 7
        if (strpos(strtolower($name), "create") === 0) {
122 7
            $class = strtolower(substr($name, 6));
123 7
            $config = (isset($arguments) && isset($arguments[0])) ? $arguments[0] : [];
124 7
            return $this->createSubsidiary($class, $config);
125
        }
126
        return parent::__call($name, $arguments);
127
    }
128
129
    /**
130
     * Find existed, or create new model.
131
     * If model to be found doesn't exist, and $config is null, the parameter
132
     * `$condition` will be regarded as properties of new model.
133
     * If you want to know whether the returned model is new model, please check
134
     * the return value of `getIsNewRecord()` method.
135
     * @param string $className Full qualified class name.
136
     * @param array $condition Search condition, or properties if not found and
137
     * $config is null.
138
     * @param array $config new model's configuration array. If you specify this
139
     * parameter, the $condition will be skipped when created one.
140
     * @return [[$className]] the existed model, or new model created by specified
0 ignored issues
show
Documentation introduced by
The doc-type [[$className]] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
141
     * condition or configuration.
142
     */
143 1
    public function findOneOrCreate($className, $condition = [], $config = null)
144
    {
145 1
        $entity = new $className(['skipInit' => true]);
146 1
        if (!isset($condition[$entity->createdByAttribute])) {
147 1
            $condition[$entity->createdByAttribute] = $this->getGUID();
0 ignored issues
show
Documentation Bug introduced by
The method getGUID does not exist on object<rhosocial\base\mo...traits\SubsidiaryTrait>? 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...
148
        }
149 1
        $model = $className::findOne($condition);
150 1
        if (!$model) {
151 1
            if ($config === null || !is_array($config)) {
152 1
                $config = $condition;
153
            }
154 1
            $model = $this->create($className, $config);
155
        }
156 1
        return $model;
157
    }
158
159
    /**
160
     * Create new entity model associated with current user. The model to be created
161
     * must be extended from [[BaseBlameableModel]], [[BaseMongoBlameableModel]],
162
     * [[BaseRedisBlameableModel]], or any other classes used [[BlameableTrait]].
163
     * if $config does not specify `hostClass` property, self will be assigned to.
164
     * @param string $className Full qualified class name.
165
     * @param array $config name-value pairs that will be used to initialize
166
     * the object properties.
167
     * @param boolean $loadDefault Determines whether loading default values
168
     * after entity model created.
169
     * Notice! The [[\yii\mongodb\ActiveRecord]] and [[\yii\redis\ActiveRecord]]
170
     * does not support loading default value. If you want to assign properties
171
     * with default values, please define the `default` rule(s) for properties in
172
     * `rules()` method and return them by yourself if you don't specified them in config param.
173
     * @param boolean $skipIfSet whether existing value should be preserved.
174
     * This will only set defaults for attributes that are `null`.
175
     * @return [[$className]] new model created with specified configuration.
0 ignored issues
show
Documentation introduced by
The doc-type [[$className]] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
176
     */
177 168
    public function create($className, $config = [], $loadDefault = true, $skipIfSet = true)
178
    {
179 168
        if (!isset($config['hostClass'])) {
180 168
            $config['hostClass'] = static::class;
181
        }
182 168
        if (isset($config['class'])) {
183 18
            unset($config['class']);
184
        }
185 168
        $entity = new $className($config);
186 168
        $entity->setHost($this);
187 168
        if ($loadDefault && method_exists($entity, 'loadDefaultValues')) {
188 85
            $entity->loadDefaultValues($skipIfSet);
189
        }
190 168
        return $entity;
191
    }
192
193
    /**
194
     *
195
     * @param string $name
196
     * @param array $config
197
     * @return type
198
     */
199 7
    public function createSubsidiary($name, $config)
200
    {
201 7
        if (!is_string($name) || empty($name)) {
202
            return null;
203
        }
204 7
        $className = '';
0 ignored issues
show
Unused Code introduced by
$className is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
205 7
        if (class_exists($name)) {
206 1
            $className = $name;
207 7
        } elseif (array_key_exists($name, $this->subsidiaryMap)) {
208 7
            $className = $this->getSubsidiaryClass($name);
209
        } else {
210 1
            return null;
211
        }
212 7
        return $this->create($className, $config);
213
    }
214
}
215