Completed
Push — master ( fa3ca9...034150 )
by vistart
05:25
created

SubsidiaryTrait::addSubsidiary()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

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