TranslatedBehavior::getRelation()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 5
cp 0.8
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.032
1
<?php
2
/**
3
 * @link https://github.com/LAV45/yii2-translated-behavior
4
 * @copyright Copyright (c) 2015 LAV45!
5
 * @author Alexey Loban <[email protected]>
6
 * @license http://opensource.org/licenses/BSD-3-Clause
7
 */
8
9
namespace lav45\translate;
10
11
use yii\base\InvalidConfigException;
12
use yii\db\ActiveRecord;
13
use yii\helpers\ArrayHelper;
14
15
/**
16
 * Class TranslatedBehavior
17
 * @package lav45\translate\TranslatedBehavior
18
 *
19
 * ================ Example use ================
20
 * public function behaviors()
21
 * {
22
 *     return [
23
 *         [
24
 *             'class' => TranslatedBehavior::className(),
25
 *             'translateRelation' => 'postLangs',
26
 *             'translateAttributes' => [
27
 *                 'titleLang' => 'title',
28
 *                 'description',
29
 *             ]
30
 *         ]
31
 *     ];
32
 * }
33
 *
34
 * @property ActiveRecord[] $currentTranslate
35
 * @property array $hasTranslate
36
 * @property ActiveRecord $translation
37
 * @property ActiveRecord $owner
38
 */
39
class TranslatedBehavior extends BaseTranslatedBehavior
40
{
41
    /**
42
     * @var string the translations relation name
43
     */
44
    public $translateRelation;
45
    /**
46
     * @var string the translations model language attribute name
47
     */
48
    public $languageAttribute = 'lang_id';
49
50
    /**
51
     * @inheritdoc
52
     */
53 17
    public function events()
54
    {
55
        return [
56 17
            ActiveRecord::EVENT_BEFORE_DELETE => 'eventBeforeDelete',
57 17
            ActiveRecord::EVENT_AFTER_INSERT => 'eventAfterSave',
58 17
            ActiveRecord::EVENT_AFTER_UPDATE => 'eventAfterSave',
59
        ];
60
    }
61
62 4
    public function eventAfterSave()
63
    {
64 4
        $this->owner->link($this->translateRelation, $this->getTranslation());
65 4
    }
66
67 1
    public function eventBeforeDelete()
68
    {
69 1
        $this->owner->unlinkAll($this->translateRelation, true);
70 1
    }
71
72
    /**
73
     * Returns the translation model for the specified language.
74
     * @param string|null $language
75
     * @return ActiveRecord
76
     */
77 11
    public function getTranslation($language = null)
78
    {
79 11
        $language = $language ?: $this->getLanguage();
80
81 11
        $translations = $this->getTranslateRelations();
82 11
        if (isset($translations[$language])) {
83 11
            return $translations[$language];
84
        }
85
86 7
        $sourceLanguage = $this->getSourceLanguage();
87 7
        $attributes = isset($translations[$sourceLanguage]) ?
88 7
            ArrayHelper::toArray($translations[$sourceLanguage]) : [];
89
90 7
        $translations[$language] = $this->createTranslation($language, $attributes);
91
92 7
        $this->setTranslateRelations($translations);
93
94 7
        return $translations[$language];
95
    }
96
97
    /**
98
     * @return ActiveRecord[]
99
     */
100 11
    protected function getTranslateRelations()
101
    {
102 11
        if ($this->owner->isRelationPopulated($this->translateRelation)) {
103 11
            $translations = ArrayHelper::index($this->owner->__get($this->translateRelation), $this->languageAttribute);
104 11
            $this->setTranslateRelations($translations);
105
        } else {
106 10
            $this->setTranslateRelations($this->owner['currentTranslate']);
107
        }
108 11
        return $this->owner->__get($this->translateRelation);
109
    }
110
111
    /**
112
     * @param ActiveRecord[] $models
113
     */
114 11
    protected function setTranslateRelations($models)
115
    {
116 11
        $this->owner->populateRelation($this->translateRelation, $models);
117 11
    }
118
119
    /**
120
     * @param string $language
121
     * @param array $attributes
122
     * @return ActiveRecord
123
     */
124 7
    protected function createTranslation($language, $attributes = [])
125
    {
126 7
        $class = $this->getRelation()->modelClass;
127
        /** @var ActiveRecord $model */
128 7
        $model = new $class();
129 7
        $attributes[$this->languageAttribute] = $language;
130 7
        $model->setAttributes($attributes, false);
131 7
        return $model;
132
    }
133
134
    /**
135
     * @return \yii\db\ActiveQuery
136
     */
137 14
    protected function getRelation()
138
    {
139
        /** @var \yii\db\ActiveQuery $relation */
140 14
        $relation = $this->owner->getRelation($this->translateRelation);
141 14
        if ($relation->multiple === false) {
142
            throw new InvalidConfigException("{$this->translateRelation} must have a one-to-many relationship ->hasMany()");
143
        }
144 14
        return $relation;
145
    }
146
147
    /**
148
     * @inheritdoc
149
     */
150 14
    public function canGetProperty($name, $checkVars = true)
151
    {
152 14
        return $this->isAttribute($name) ||
153 12
            parent::canGetProperty($name, $checkVars) ||
154 14
            (is_object($this->getTranslation()) && $this->getTranslation()->canGetProperty($name, $checkVars));
155
    }
156
157
    /**
158
     * @inheritdoc
159
     */
160 9
    public function canSetProperty($name, $checkVars = true)
161
    {
162 9
        return $this->isAttribute($name) ||
163 6
            parent::canSetProperty($name, $checkVars) ||
164 9
            (is_object($this->getTranslation()) && $this->getTranslation()->canSetProperty($name, $checkVars));
165
    }
166
167
    /**
168
     * @inheritdoc
169
     */
170 14
    public function __get($name)
171
    {
172 14
        $getter = 'get' . $name;
173 14
        if (method_exists($this, $getter)) {
174 12
            return $this->$getter();
175
        }
176 6
        $name = $this->getTranslateAttributeName($name) ?: $name;
177 6
        return $this->getTranslation()[$name];
178
    }
179
180
    /**
181
     * @inheritdoc
182
     */
183 17
    public function __set($name, $value)
184
    {
185 17
        $setter = 'set' . $name;
186 17
        if (method_exists($this, $setter)) {
187 17
            $this->$setter($value);
188
        } else {
189 7
            $name = $this->getTranslateAttributeName($name) ?: $name;
190 7
            $this->getTranslation()[$name] = $value;
191
        }
192 17
    }
193
194
    /**
195
     * Returns a value indicating whether a method is defined.
196
     *
197
     * The default implementation is a call to php function `method_exists()`.
198
     * You may override this method when you implemented the php magic method `__call()`.
199
     * @param string $name the method name
200
     * @return boolean whether the method is defined
201
     */
202 10
    public function hasMethod($name)
203
    {
204 10
        return parent::hasMethod($name) ||
205 10
            (is_object($this->getTranslation()) && $this->getTranslation()->hasMethod($name));
206
    }
207
208
    /**
209
     * Calls the named method which is not a class method.
210
     *
211
     * Do not call this method directly as it is a PHP magic method that
212
     * will be implicitly called when an unknown method is being invoked.
213
     * @param string $name the method name
214
     * @param array $params method parameters
215
     * @return mixed the method return value
216
     */
217 1
    public function __call($name, $params)
218
    {
219 1
        return call_user_func_array([$this->getTranslation(), $name], $params);
220
    }
221
222
    /**
223
     * @return bool
224
     */
225 1
    public function isTranslated()
226
    {
227 1
        return $this->isSourceLanguage() === false && $this->getTranslation()->getIsNewRecord() === false;
228
    }
229
230
    /**
231
     * This read only relations designed for method $this->hasTranslate()
232
     * @return \yii\db\ActiveQuery
233
     */
234 3
    public function getHasTranslate()
235
    {
236 3
        $relations = $this->getRelation();
237 3
        $select = array_keys($relations->link);
238 3
        $select[] = $this->languageAttribute;
239
240
        return $relations
241 3
            ->select($select)
242 3
            ->indexBy($this->languageAttribute)
243 3
            ->asArray();
244
    }
245
246
    /**
247
     * @return \yii\db\ActiveQuery
248
     */
249 12
    public function getCurrentTranslate()
250
    {
251 12
        $langList = [$this->getLanguage(), $this->getSourceLanguage()];
252 12
        $langList = array_keys(array_flip($langList));
253
        /** @var ActiveRecord $class */
254 12
        $class = $this->getRelation()->modelClass;
255 12
        $table = $class::tableName();
256
257 12
        return $this->getRelation()
258 12
            ->onCondition([$table . '.' . $this->languageAttribute => $langList])
259 12
            ->indexBy($this->languageAttribute);
260
    }
261
}
262