SubsidiaryTrait::getSubsidiaries()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.0175

Importance

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