Test Failed
Push — master ( 5196a6...aaaa1a )
by vistart
08:44
created

SubsidiaryTrait   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 95.52%

Importance

Changes 3
Bugs 0 Features 3
Metric Value
wmc 36
c 3
b 0
f 3
lcom 1
cbo 1
dl 0
loc 193
ccs 64
cts 67
cp 0.9552
rs 8.8

8 Methods

Rating   Name   Duplication   Size   Complexity  
A removeSubsidiary() 0 9 2
A getSubsidiaryClass() 0 8 4
A getSubsidiaries() 0 12 3
A __call() 0 9 4
B findOneOrCreate() 0 15 5
B create() 0 15 5
B createSubsidiary() 0 15 5
B addSubsidiary() 0 21 8
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
     *         'max' => 1,
40
     *     ]
41
     * ];
42
     *
43
     * If you want to create subsidiary model and the class is not found, the array elements will be taken.
44
     */
45
    public $subsidiaryMap = [];
46
    
47
    /**
48
     * Add subsidiary.
49
     * @param string $name
50
     * @param string|array $config
51
     * @return boolean
52
     * @throws InvalidConfigException
53
     */
54 6
    public function addSubsidiary($name, $config)
55
    {
56 6
        if (!is_string($name) || empty($name)) {
57 1
            throw new InvalidConfigException('Subsidiary name not specified.');
58
        }
59 6
        $name = strtolower($name);
60 6
        if (!is_array($config)) {
61 6
            if (is_string($config) && !empty($config)) {
62 6
                $this->subsidiaryMap[$name] = ['class' => $config];
63
            } else {
64
                throw new InvalidConfigException('Subsidiary class not specified.');
65
            }
66
        } else {
67 1
            if (isset($config['class']) && class_exists($config['class'])) {
68 1
                $this->subsidiaryMap[$name] = $config;
69
            } else {
70 1
                throw new InvalidConfigException('Subsidiary class not specified.');
71
            }
72
        }
73 6
        return true;
74
    }
75
    
76
    /**
77
     * Remove subsidiary.
78
     * @param string $name
79
     * @return boolean
80
     */
81 1
    public function removeSubsidiary($name)
82
    {
83 1
        $name = strtolower($name);
84 1
        if (array_key_exists($name, $this->subsidiaryMap)) {
85 1
            unset($this->subsidiaryMap[$name]);
86 1
            return true;
87
        }
88 1
        return false;
89
    }
90
    
91
    /**
92
     * Get subsidiary class.
93
     * @param string $name
94
     * @return string
95
     */
96 6
    public function getSubsidiaryClass($name)
97
    {
98 6
        $name = strtolower($name);
99 6
        if (array_key_exists($name, $this->subsidiaryMap) && array_key_exists('class', $this->subsidiaryMap[$name])) {
100 6
            return class_exists($this->subsidiaryMap[$name]['class']) ? $this->subsidiaryMap[$name]['class'] : null;
101
        }
102 1
        return null;
103
    }
104
    
105 2
    public function getSubsidiaries($name, $limit = 'all', $page = 0)
106
    {
107 2
        $class = $this->getSubsidiaryClass($name);
108 2
        if (empty($class)) {
109 1
            return null;
110
        }
111 2
        $query = $class::find();
112 2
        if (!method_exists($query, 'createdBy')) {
113
            return null;
114
        }
115 2
        return $class::find()->createdBy($this)->page($limit, $page)->all();
116
    }
117
    
118 6
    public function __call($name, $arguments)
119
    {
120 6
        if (strpos(strtolower($name), "create") === 0) {
121 6
            $class = strtolower(substr($name, 6));
122 6
            $config = (isset($arguments) && isset($arguments[0])) ? $arguments[0] : [];
123 6
            return $this->createSubsidiary($class, $config);
124
        }
125
        return parent::__call($name, $arguments);
126
    }
127
128
    /**
129
     * Find existed, or create new model.
130
     * If model to be found doesn't exist, and $config is null, the parameter
131
     * `$condition` will be regarded as properties of new model.
132
     * If you want to know whether the returned model is new model, please check
133
     * the return value of `getIsNewRecord()` method.
134
     * @param string $className Full qualified class name.
135
     * @param array $condition Search condition, or properties if not found and
136
     * $config is null.
137
     * @param array $config new model's configuration array. If you specify this
138
     * parameter, the $condition will be skipped when created one.
139
     * @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...
140
     * condition or configuration.
141
     */
142 1
    public function findOneOrCreate($className, $condition = [], $config = null)
143
    {
144 1
        $entity = new $className(['skipInit' => true]);
145 1
        if (!isset($condition[$entity->createdByAttribute])) {
146 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...
147
        }
148 1
        $model = $className::findOne($condition);
149 1
        if (!$model) {
150 1
            if ($config === null || !is_array($config)) {
151 1
                $config = $condition;
152
            }
153 1
            $model = $this->create($className, $config);
154
        }
155 1
        return $model;
156
    }
157
158
    /**
159
     * Create new entity model associated with current user. The model to be created
160
     * must be extended from [[BaseBlameableModel]], [[BaseMongoBlameableModel]],
161
     * [[BaseRedisBlameableModel]], or any other classes used [[BlameableTrait]].
162
     * if $config does not specify `hostClass` property, self will be assigned to.
163
     * @param string $className Full qualified class name.
164
     * @param array $config name-value pairs that will be used to initialize
165
     * the object properties.
166
     * @param boolean $loadDefault Determines whether loading default values
167
     * after entity model created.
168
     * Notice! The [[\yii\mongodb\ActiveRecord]] and [[\yii\redis\ActiveRecord]]
169
     * does not support loading default value. If you want to assign properties
170
     * with default values, please define the `default` rule(s) for properties in
171
     * `rules()` method and return them by yourself if you don't specified them in config param.
172
     * @param boolean $skipIfSet whether existing value should be preserved.
173
     * This will only set defaults for attributes that are `null`.
174
     * @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...
175
     */
176 167
    public function create($className, $config = [], $loadDefault = true, $skipIfSet = true)
177
    {
178 167
        if (!isset($config['hostClass'])) {
179 167
            $config['hostClass'] = static::class;
180
        }
181 167
        if (isset($config['class'])) {
182 18
            unset($config['class']);
183
        }
184 167
        $entity = new $className($config);
185 167
        $entity->setHost($this);
186 167
        if ($loadDefault && method_exists($entity, 'loadDefaultValues')) {
187 84
            $entity->loadDefaultValues($skipIfSet);
188
        }
189 167
        return $entity;
190
    }
191
192
    /**
193
     *
194
     * @param string $name
195
     * @param array $config
196
     * @return type
197
     */
198 6
    public function createSubsidiary($name, $config)
199
    {
200 6
        if (!is_string($name) || empty($name)) {
201 1
            return null;
202
        }
203 6
        $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...
204 6
        if (class_exists($name)) {
205 1
            $className = $name;
206 6
        } elseif (array_key_exists($name, $this->subsidiaryMap)) {
207 6
            $className = $this->getSubsidiaryClass($name);
208
        } else {
209 1
            return null;
210
        }
211 6
        return $this->create($className, $config);
212
    }
213
}
214