Completed
Push — master ( 5c5d70...bd2d7d )
by Loban
05:49
created

TranslatedBehavior::getTranslation()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

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