TranslationBehavior   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 11
Bugs 1 Features 4
Metric Value
wmc 18
c 11
b 1
f 4
lcom 1
cbo 7
dl 0
loc 287
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
B addSortI18ns() 0 31 2
B getToStringMethod() 0 56 7
A getI18nsMethod() 0 66 1
A CamelCase() 0 4 1
A objectFilter() 0 15 1
A queryFilter() 0 8 1
B getUseI18nQueryMethod() 0 38 4
A exceptionError() 0 13 1
1
<?php
2
3
namespace ItBlaster\TranslationBundle\Behavior;
4
use ItBlaster\TranslationBundle\Traits\TranslationTrait;
5
6
/**
7
 * Базовый класс
8
 *
9
 * Class TranslationBehavior
10
 * @package ItBlaster\TranslationBundle\Behavior
11
 */
12
abstract class TranslationBehavior extends \Behavior
13
{
14
    use TranslationTrait;
15
16
    protected $parameters = array(
17
        'primary_string'  => '',
18
    );
19
20
    /**
21
     * Метож сортировки элементов языковых версий
22
     *
23
     * @param $script
24
     */
25
    protected function addSortI18ns(&$script)
26
    {
27
        $locales = $this->getLocales();
28
        $langs = "array(";
29
        foreach ($locales as $locale) {
30
            $langs.='"'.$locale.'",';
31
        }
32
        $langs.=')';
33
34
        $script .= '
35
/**
36
 * Сортирует элементы массива по порядку следования языков
37
 *
38
 * @param $elementsf
39
 * @return array
40
 */
41
protected function sortI18ns($elements) {
42
    if (count($elements)) {
43
        $result = new \PropelObjectCollection();
44
        $langs = array_flip('.$langs.');
45
        foreach($elements as $element) {
46
            $result[$langs[$element->getLocale()]] = $element;
47
        }
48
        $result->ksort();
49
        return $result;
50
    } else {
51
        return $elements;
52
    }
53
}
54
    ';
55
    }
56
57
    /**
58
     * Переопределение метода _toString
59
     *
60
     * @return string
61
     * @throws \Exception
62
     */
63
    protected function getToStringMethod()
64
    {
65
        $primary_string = $this->getParameter('primary_string');
66
        $i18n_languages = $this->getLocales();
67
        $primary_string_column =  count($i18n_languages) ? $primary_string : $this->getColumnForParameter('primary_string');
68
        $get_primary_string = 'get'.(count($i18n_languages) ? $this->CamelCase($primary_string) : $primary_string_column->getPhpName());
69
70
        if(!$primary_string_column) {
71
            $this->exceptionError('Not found column "'.$primary_string.'" in table '.$this->getTable()->getName());
72
        }
73
74
        $toString = '
75
76
    /**
77
     * Отдаём PrimaryString
78
     *
79
     * @return string
80
     */
81
    public function __toString() {';
82
83
        //есть языковые версии
84
        if (count($i18n_languages)) {
85
            $languages = 'array(';
86
            foreach ($i18n_languages as $lang) {
87
                $languages.='"'.$lang.'",';
88
            }
89
            $languages.=')';
90
91
            $toString .= '
92
        $to_string = $this->isNew() ? "New object" : "";
93
        $languages = '.$languages.';
94
        foreach ($languages as $language) {
95
            $str = $this->setLocale($language)->'.$get_primary_string.'();
96
            if ($str) {
97
		        $to_string = $str;
98
                break;
99
            }
100
        }
101
        if (mb_strlen($to_string, "UTF-8")>26) {
102
            $to_string = mb_substr($to_string, 0, 26, "utf-8")."...";
103
        }
104
        ';
105
            if ($this->getTable()->hasColumn('slug')) {
106
                $toString .= '$to_string = $to_string ? $to_string : $this->getSlug();
107
        ';
108
            }
109
        $toString .= 'return $to_string;';
110
        } else { //нет языковых версий
111
            $toString .= '
112
        return $this->'.$get_primary_string.'() ? $this->'.$get_primary_string.'() : "New object";';
113
        }
114
        $toString .= '
115
    }
116
    ';
117
        return $toString;
118
    }
119
120
    /**
121
     * Перелпределение метода getI18ns
122
     *
123
     * @return string
124
     */
125
    protected function getI18nsMethod()
126
    {
127
        $class_name = $this->CamelCase($this->getTable()->getName());
128
        $get_i18ns_method = '
129
    /**
130
     * Gets an array of '.$class_name.'I18n objects which contain a foreign key that references this object.
131
     *
132
     * If the $criteria is not null, it is used to always fetch the results from the database.
133
     * Otherwise the results are fetched from the database the first time, then cached.
134
     * Next time the same method is called without $criteria, the cached collection is returned.
135
     * If this FaqQuestionGroup is new, it will return
136
     * an empty collection or the current collection; the criteria is ignored on a new object.
137
     *
138
     * @param Criteria $criteria optional Criteria object to narrow the query
139
     * @param PropelPDO $con optional connection object
140
     * @return PropelObjectCollection|'.$class_name.'I18n[] List of '.$class_name.'I18n objects
141
     * @throws PropelException
142
     */
143
    public function get'.$class_name.'I18ns($criteria = null, PropelPDO $con = null)
144
    {
145
        $partial = $this->coll'.$class_name.'I18nsPartial && !$this->isNew();
146
        if (null === $this->coll'.$class_name.'I18ns || null !== $criteria  || $partial) {
147
            if ($this->isNew() && null === $this->coll'.$class_name.'I18ns) {
148
                // return empty collections
149
                $this->init'.$class_name.'I18ns();
150
            } else {
151
                $coll'.$class_name.'I18ns = '.$class_name.'I18nQuery::create(null, $criteria)
152
                    ->filterBy'.$class_name.'($this)
153
                    ->find($con);
154
                $coll'.$class_name.'I18ns = $this->sortI18ns($coll'.$class_name.'I18ns);
155
                if (null !== $criteria) {
156
                    if (false !== $this->coll'.$class_name.'I18nsPartial && count($coll'.$class_name.'I18ns)) {
157
                      $this->init'.$class_name.'I18ns(false);
158
159
                      foreach ($coll'.$class_name.'I18ns as $obj) {
160
                        if (false == $this->coll'.$class_name.'I18ns->contains($obj)) {
161
                          $this->coll'.$class_name.'I18ns->append($obj);
162
                        }
163
                      }
164
165
                      $this->coll'.$class_name.'I18nsPartial = true;
166
                    }
167
168
                    $coll'.$class_name.'I18ns->getInternalIterator()->rewind();
169
170
                    return $coll'.$class_name.'I18ns;
171
                }
172
173
                if ($partial && $this->coll'.$class_name.'I18ns) {
174
                    foreach ($this->coll'.$class_name.'I18ns as $obj) {
175
                        if ($obj->isNew()) {
176
                            $coll'.$class_name.'I18ns[] = $obj;
177
                        }
178
                    }
179
                }
180
181
                $this->coll'.$class_name.'I18ns = $coll'.$class_name.'I18ns;
182
                $this->coll'.$class_name.'I18nsPartial = false;
183
            }
184
        }
185
186
        return $this->coll'.$class_name.'I18ns;
187
    }
188
        ';
189
        return $get_i18ns_method;
190
    }
191
192
    /**
193
     * Перевод из венгерского стиля в CamelCase
194
     *
195
     * @param $name
196
     * @return mixed
197
     */
198
    protected function CamelCase($name)
199
    {
200
        return ucfirst(\Propel\PropelBundle\Util\PropelInflector::camelize($name));
201
    }
202
203
    /**
204
     * Переопределяем метод __toString
205
     *
206
     * @param $script
207
     */
208
    public function objectFilter(&$script)
209
    {
210
        $to_string_method = $this->getToStringMethod();
211
        $get_i18ns_method = $this->getI18nsMethod();
212
        $i18ns_method_name = 'get'.$this->CamelCase($this->getTable()->getName()).'I18ns';
213
214
        $table = $this->getTable();
215
        $newToStringMethod = sprintf($to_string_method, $table->getName(), $table->getPhpName(), $table->getPhpName());
216
        $newI18nMethod = sprintf($get_i18ns_method, $table->getName(), $table->getPhpName(), $table->getPhpName());
217
218
        $parser = new \PropelPHPParser($script, true);
219
        $parser->replaceMethod('__toString', $newToStringMethod);
220
        $parser->replaceMethod($i18ns_method_name, $newI18nMethod);
221
        $script = $parser->getCode();
222
    }
223
224
    public function queryFilter(&$script, $builder)
225
    {
226
        $useI18nQueryMethod = $this->getUseI18nQueryMethod($builder);
227
228
        $parser = new \PropelPHPParser($script, true);
229
        $parser->replaceMethod('useI18nQuery', $useI18nQueryMethod);
230
        $script = $parser->getCode();
231
    }
232
233
    /**
234
     * Добавляем неймспейс к phpDoc-у
235
     *
236
     * @param \QueryBuilder $builder
237
     *
238
     * @return string
239
     */
240
    protected function getUseI18nQueryMethod(\QueryBuilder $builder)
241
    {
242
243
        $currentTable = $this->getTable();
244
        $db = $currentTable->getDatabase();
245
246
        $i18nTableName = $currentTable->getName() . '_i18n';
247
        $i18nTable = $db->getTable($i18nTableName);
248
        if (!$i18nTable) {
249
            $this->exceptionError('Table '.$i18nTableName.' not found');
250
        }
251
        foreach ($i18nTable->getForeignKeys() as $fk) {
252
            if ($fk->getForeignTableName() == $currentTable->getName()) {
253
                $foreignKey = $fk;
254
            }
255
        }
256
257
        $script = '
258
259
    /**
260
     * Use the I18n relation query object
261
     *
262
     * @see       useQuery()
263
     *
264
     * @param     string $locale Locale to use for the join condition, e.g. \'fr_FR\'
265
     * @param     string $relationAlias optional alias for the relation
266
     * @param     string $joinType Accepted values are null, \'left join\', \'right join\', \'inner join\'. Defaults to left join.
267
     *
268
     * @return    \\' . $builder->getNewStubQueryBuilder($i18nTable)->getFullyQualifiedClassname() . ' A secondary query class using the current class as primary query
0 ignored issues
show
Bug introduced by
It seems like $i18nTable defined by $db->getTable($i18nTableName) on line 247 can be null; however, DataModelBuilder::getNewStubQueryBuilder() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
269
     */
270
    public function useI18nQuery($locale = \'ru\', $relationAlias = null, $joinType = Criteria::LEFT_JOIN)
271
    {
272
        return $this
273
            ->joinI18n($locale, $relationAlias, $joinType)
274
            ->useQuery($relationAlias ? $relationAlias : \''. $builder->getRefFKPhpNameAffix($foreignKey) .'\', \'\\'. $builder->getNewStubQueryBuilder($i18nTable)->getFullyQualifiedClassname() .'\');
0 ignored issues
show
Bug introduced by
The variable $foreignKey does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
It seems like $i18nTable defined by $db->getTable($i18nTableName) on line 247 can be null; however, DataModelBuilder::getNewStubQueryBuilder() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
275
    }';
276
        return $script;
277
    }
278
279
    /**
280
     * Выкидываем эксепшн с ошибкой
281
     *
282
     * @param $error
283
     * @throws \Exception
284
     */
285
    protected function exceptionError($error)
286
    {
287
        throw new \Exception('
288
289
290
291
        <------ERROR------- '.$error.' ------ERROR------->
292
293
294
295
296
        ');
297
    }
298
}