Issues (18)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Behavior/ExtendedSluggableBehavior.php (10 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace ItBlaster\TranslationBundle\Behavior;
4
5
class ExtendedSluggableBehavior extends TranslationBehavior
6
{
7
    // default parameters value
8
    protected $parameters = array(
9
        'add_cleanup'     => 'true',
10
        'slug_column'     => 'slug',
11
        'slug_pattern'    => '',
12
        'replace_pattern' => '/\W+/', // Tip: use '/[^\\pL\\d]+/u' instead if you're in PHP5.3
13
        'replacement'     => '-',
14
        'separator'       => '-',
15
        'permanent'       => 'false',
16
        'scope_column'    => '',
17
        'primary_string'  => '',
18
    );
19
20
    /**
21
     * Add the slug_column to the current table
22
     */
23
    public function modifyTable()
24
    {
25
        $table = $this->getTable();
26
        $primary_string = $this->getParameter('primary_string');
27
28
        if (!$primary_string) {
29
            $this->exceptionError('Need set parameter "primary_string" in table '.$table->getName());
30
        }
31
32
        if (!$table->hasColumn($primary_string)) {
33
            $this->exceptionError('Not found column "'.$primary_string.'" in table '.$table->getName());
34
        }
35
36
        if (!$this->getTable()->containsColumn($this->getParameter('slug_column'))) {
0 ignored issues
show
Deprecated Code introduced by
The method Table::containsColumn() has been deprecated with message: use hasColumn() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
37
            $this->getTable()->addColumn(array(
38
                'name' => $this->getParameter('slug_column'),
39
                'type' => 'VARCHAR',
40
                'size' => 255
41
            ));
42
            // add a unique to column
43
            $unique = new \Unique($this->getColumnForParameter('slug_column'));
0 ignored issues
show
It seems like $this->getColumnForParameter('slug_column') targeting Behavior::getColumnForParameter() can also be of type object<Column>; however, Index::__construct() does only seem to accept string|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
44
            $unique->setName($this->getTable()->getCommonName() . '_slug');
45
            $unique->addColumn($this->getTable()->getColumn($this->getParameter('slug_column')));
46
            if ($this->getParameter('scope_column')) {
47
                $unique->addColumn($this->getTable()->getColumn($this->getParameter('scope_column')));
48
            }
49
            $this->getTable()->addUnique($unique);
50
        }
51
    }
52
53
    /**
54
     * Get the getter of the column of the behavior
55
     *
56
     * @return string The related getter, e.g. 'getSlug'
57
     */
58
    protected function getColumnGetter()
59
    {
60
        return 'get' . $this->getColumnForParameter('slug_column')->getPhpName();
61
    }
62
63
    /**
64
     * Get the setter of the column of the behavior
65
     *
66
     * @return string The related setter, e.g. 'setSlug'
67
     */
68
    protected function getColumnSetter()
69
    {
70
        return 'set' . $this->getColumnForParameter('slug_column')->getPhpName();
71
    }
72
73
    /**
74
     * Add code in ObjectBuilder::preSave
75
     *
76
     * @return string The code to put at the hook
77
     */
78
    public function preSave(\PHP5ObjectBuilder $builder)
79
    {
80
        $const = $builder->getColumnConstant($this->getColumnForParameter('slug_column'));
0 ignored issues
show
It seems like $this->getColumnForParameter('slug_column') can be null; however, getColumnConstant() 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...
81
        $pattern = $this->getParameter('slug_pattern');
82
        $script = "
83
if (\$this->isColumnModified($const) && \$this->{$this->getColumnGetter()}()) {
84
    \$this->{$this->getColumnSetter()}(\$this->makeSlugUnique(\$this->{$this->getColumnGetter()}()));";
85
86
        if ($pattern && false === $this->booleanValue($this->getParameter('permanent'))) {
87
            $script .= "
88
} elseif (";
89
            $count = preg_match_all('/{([a-zA-Z]+)}/', $pattern, $matches, PREG_PATTERN_ORDER);
90
91
            foreach ($matches[1] as $key => $match) {
92
                $columnName = $this->underscore(ucfirst($match));
93
                $column = $this->getTable()->getColumn($columnName);
94
                if ((null == $column) && $this->getTable()->hasBehavior('symfony_i18n')) {
95
                    $i18n = $this->getTable()->getBehavior('symfony_i18n');
96
                    $column = $i18n->getI18nTable()->getColumn($columnName);
97
                }
98
                if (null == $column) {
99
                    throw new \InvalidArgumentException(sprintf('The pattern %s is invalid  the column %s is not found', $pattern, $match));
100
                }
101
                $columnConst = $builder->getColumnConstant($column);
102
                $script .= "\$this->isColumnModified($columnConst)" . ($key < $count - 1 ? " || " : "");
103
            }
104
105
            $script .= ") {
106
    \$this->{$this->getColumnSetter()}(\$this->createSlug());";
107
        }
108
109
        if (null == $pattern && false === $this->booleanValue($this->getParameter('permanent'))) {
110
            $script .= "
111
} else {
112
    \$this->{$this->getColumnSetter()}(\$this->createSlug());
113
}";
114
        } else {
115
            $script .= "
116
} elseif (!\$this->{$this->getColumnGetter()}()) {
117
    \$this->{$this->getColumnSetter()}(\$this->createSlug());
118
}";
119
        }
120
121
        return $script;
122
    }
123
124
    public function objectMethods(\PHP5ObjectBuilder $builder)
125
    {
126
        $this->builder = $builder;
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
127
        $script = '';
128
        if ('slug' != $this->getParameter('slug_column')) {
129
            $this->addSlugSetter($script);
130
            $this->addSlugGetter($script);
131
        }
132
        $this->addCreateSlug($script);
133
        $this->addCreateRawSlug($script);
134
        if ($this->booleanValue($this->getParameter('add_cleanup'))) {
135
            $this->addCleanupSlugPart($script);
136
        }
137
        $this->addLimitSlugSize($script);
138
        $this->addMakeSlugUnique($script);
139
140
        $this->addSortI18ns($script);
141
        $this->addToSlug($script);
142
143
        return $script;
144
    }
145
146
    protected function addSlugSetter(&$script)
147
    {
148
        $script .= "
149
/**
150
 * Wrap the setter for slug value
151
 *
152
 * @param   string
153
 * @return  " . $this->getTable()->getPhpName() . "
154
 */
155
public function setSlug(\$v)
156
{
157
    return \$this->" . $this->getColumnSetter() . "(\$v);
158
}
159
";
160
    }
161
162
    protected function addSlugGetter(&$script)
163
    {
164
        $script .= "
165
/**
166
 * Wrap the getter for slug value
167
 *
168
 * @return  string
169
 */
170
public function getSlug()
171
{
172
    return \$this->" . $this->getColumnGetter() . "();
173
}
174
";
175
    }
176
177
    protected function addCreateSlug(&$script)
178
    {
179
        $script .= "
180
/**
181
 * Create a unique slug based on the object
182
 *
183
 * @return string The object slug
184
 */
185
protected function createSlug()
186
{
187
    \$slug = \$this->createRawSlug();
188
    \$slug = \$this->limitSlugSize(\$slug);
189
    \$slug = \$this->makeSlugUnique(\$slug);
190
191
    return \$slug;
192
}
193
";
194
    }
195
196
197
    /**
198
     * Метод для формирования Slug
199
     *
200
     * @param $script
201
     */
202
    protected function addToSlug(&$script)
203
    {
204
205
        $primary_string = $this->getParameter('primary_string');
206
        $i18n_languages = $this->getSlugLocales();
207
        $primary_string_column =  count($i18n_languages) ? $primary_string : $this->getColumnForParameter('primary_string');
208
        $get_primary_string = 'get'.(count($i18n_languages) ? $this->CamelCase($primary_string) : $primary_string_column->getPhpName());
209
210
        if(!$primary_string_column) {
211
            $this->exceptionError('Not found column "'.$primary_string.'" in table '.$this->getTable()->getName());
212
        }
213
214
        $toSlug = '
215
/**
216
 * Метод для формирования Slug
217
 *
218
 * @return string
219
 */
220
protected function toSlug() {';
221
222
        //есть языковые версии
223
        if (count($i18n_languages)) {
224
            $languages = 'array(';
225
            foreach ($i18n_languages as $lang) {
226
                $languages.='"'.$lang.'",';
227
            }
228
            $languages.=')';
229
230
            $toSlug .= '
231
        $to_string = $this->isNew() ? "Новая запись" : "";
232
        $languages = '.$languages.';
233
        foreach ($languages as $language) {
234
            $str = $this->setLocale($language)->'.$get_primary_string.'();
235
            if ($str) {
236
                return $str;
237
            }
238
        }
239
        return $to_string;';
240
        } else { //нет языковых версий
241
            $toSlug .= '
242
        return $this->'.$get_primary_string.'() ? $this->'.$get_primary_string.'() : "Новая запись";';
243
        }
244
        $toSlug .= '
245
    }
246
    ';
247
        $script .= $toSlug;
248
    }
249
250
    protected function addCreateRawSlug(&$script)
251
    {
252
        $pattern = $this->getParameter('slug_pattern');
253
        $script .= "
254
/**
255
 * Create the slug from the appropriate columns
256
 *
257
 * @return string
258
 */
259
protected function createRawSlug()
260
{
261
    ";
262
        if ($pattern) {
263
            $script .= "return '" . str_replace(array('{', '}'), array('\' . $this->cleanupSlugPart($this->get', '()) . \''), $pattern) . "';";
264
        } else {
265
            $script .= "return \$this->cleanupSlugPart(\$this->toSlug());";
266
        }
267
        $script .= "
268
}
269
";
270
271
        return $script;
272
    }
273
274
    public function addCleanupSlugPart(&$script)
275
    {
276
        $script .= "
277
/**
278
 * Cleanup a string to make a slug of it
279
 * Removes special characters, replaces blanks with a separator, and trim it
280
 *
281
 * @param     string \$slug        the text to slugify
282
 * @param     string \$replacement the separator used by slug
283
 * @return    string               the slugified text
284
 */
285
protected static function cleanupSlugPart(\$slug, \$replacement = '" . $this->getParameter('replacement') . "')
286
{
287
    \$slug = strtr(\$slug, array(
288
        'А' => 'A',  'Б' => 'B',  'В' => 'V',    'Г' => 'G',    'Д' => 'D', 'Е' => 'E', 'Ё' => 'E',  'Ж' => 'ZH',
289
        'З' => 'Z',  'И' => 'I',  'Й' => 'Y',    'К' => 'K',    'Л' => 'L', 'М' => 'M', 'Н' => 'N',  'О' => 'O',
290
        'П' => 'P',  'Р' => 'R',  'С' => 'S',    'Т' => 'T',    'У' => 'U', 'Ф' => 'F', 'Х' => 'KH', 'Ц' => 'TS',
291
        'Ч' => 'CH', 'Ш' => 'SH', 'Щ' => 'SHCH', 'Ь' => '',     'Ы' => 'Y', 'Ъ' => '',  'Э' => 'E',  'Ю' => 'YU',
292
        'Я' => 'YA', 'а' => 'a',  'б' => 'b',    'в' => 'v',    'г' => 'g', 'д' => 'd', 'е' => 'e',  'ё' => 'e',
293
        'ж' => 'zh', 'з' => 'z',  'и' => 'i',    'й' => 'y',    'к' => 'k', 'л' => 'l', 'м' => 'm',  'н' => 'n',
294
        'о' => 'o',  'п' => 'p',  'р' => 'r',    'с' => 's',    'т' => 't', 'у' => 'u', 'ф' => 'f',  'х' => 'kh',
295
        'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh',   'щ' => 'shch', 'ь' => '',  'ы' => 'y', 'ъ' => '',   'э' => 'e',
296
        'ю' => 'yu', 'я' => 'ya'
297
    ));
298
299
    // transliterate
300
    if (function_exists('iconv')) {
301
        \$slug = iconv('utf-8', 'us-ascii//TRANSLIT', \$slug);
302
    }
303
304
    // lowercase
305
    if (function_exists('mb_strtolower')) {
306
        \$slug = mb_strtolower(\$slug);
307
    } else {
308
        \$slug = strtolower(\$slug);
309
    }
310
311
    // remove accents resulting from OSX's iconv
312
    \$slug = str_replace(array('\'', '`', '^'), '', \$slug);
313
314
    // replace non letter or digits with separator
315
    \$slug = preg_replace('" . $this->getParameter('replace_pattern') . "', \$replacement, \$slug);
316
317
    // trim
318
    \$slug = trim(\$slug, \$replacement);
319
320
    if (empty(\$slug)) {
321
        return 'n-a';
322
    }
323
324
    return \$slug;
325
}
326
";
327
    }
328
329
    public function addLimitSlugSize(&$script)
330
    {
331
        $size = $this->getColumnForParameter('slug_column')->getSize();
332
        $script .= "
333
334
/**
335
 * Make sure the slug is short enough to accommodate the column size
336
 *
337
 * @param    string \$slug                   the slug to check
338
 * @param    int    \$incrementReservedSpace the number of characters to keep empty
339
 *
340
 * @return string                            the truncated slug
341
 */
342
protected static function limitSlugSize(\$slug, \$incrementReservedSpace = 3)
343
{
344
    // check length, as suffix could put it over maximum
345
    if (strlen(\$slug) > ($size - \$incrementReservedSpace)) {
346
        \$slug = substr(\$slug, 0, $size - \$incrementReservedSpace);
347
    }
348
349
    return \$slug;
350
}
351
";
352
    }
353
354
    public function addMakeSlugUnique(&$script)
355
    {
356
        $script .= "
357
358
/**
359
 * Get the slug, ensuring its uniqueness
360
 *
361
 * @param    string \$slug            the slug to check
362
 * @param    string \$separator       the separator used by slug
363
 * @param    int    \$alreadyExists   false for the first try, true for the second, and take the high count + 1
364
 * @return   string                   the unique slug
365
 */
366
protected function makeSlugUnique(\$slug, \$separator = '" . $this->getParameter('separator') . "', \$alreadyExists = false)
367
{";
368
        $getter = $this->getColumnGetter();
369
        $script .= "
370
    if (!\$alreadyExists) {
371
        \$slug2 = \$slug;
372
    } else {
373
        \$slug2 = \$slug . \$separator;";
374
375
        if (null == $this->getParameter('slug_pattern')) {
376
            $script .= "
377
378
        \$count = " . $this->builder->getStubQueryBuilder()->getClassname() . "::create()
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
379
            ->filterBySlug(\$this->$getter())
380
            ->filterByPrimaryKey(\$this->getPrimaryKey())
381
        ->count();
382
383
        if (1 == \$count) {
384
            return \$this->$getter();
385
        }";
386
        }
387
388
        $script .= "
389
    }
390
391
     \$query = " . $this->builder->getStubQueryBuilder()->getClassname() . "::create('q')
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
392
    ";
393
        $platform = $this->getTable()->getDatabase()->getPlatform();
394
        if ($platform instanceof \PgsqlPlatform) {
395
            $script .= "->where('q." . $this->getColumnForParameter('slug_column')->getPhpName() . " ' . (\$alreadyExists ? '~*' : '=') . ' ?', \$alreadyExists ? '^' . \$slug2 . '[0-9]+$' : \$slug2)";
396
        } elseif ($platform instanceof \MssqlPlatform) {
397
            $script .= "->where('q." . $this->getColumnForParameter('slug_column')->getPhpName() . " ' . (\$alreadyExists ? 'like' : '=') . ' ?', \$alreadyExists ? '^' . \$slug2 . '[0-9]+$' : \$slug2)";
398
        } elseif ($platform instanceof \OraclePlatform) {
399
            $script .= "->where((\$alreadyExists ? 'REGEXP_LIKE(' : '') . 'q." . $this->getColumnForParameter('slug_column')->getPhpName() . " ' . (\$alreadyExists ? ',' : '=') . ' ?' . (\$alreadyExists ? ')' : ''), \$alreadyExists ? '^' . \$slug2 . '[0-9]+$' : \$slug2)";
400
        } else {
401
            $script .= "->where('q." . $this->getColumnForParameter('slug_column')->getPhpName() . " ' . (\$alreadyExists ? 'REGEXP' : '=') . ' ?', \$alreadyExists ? '^' . \$slug2 . '[0-9]+$' : \$slug2)";
402
        }
403
404
        $script .="->prune(\$this)";
405
406
        if ($this->getParameter('scope_column')) {
407
            $scopeGetter = 'get' . $this->getColumnForParameter('scope_column')->getPhpName();
408
            $script .= "
409
            ->filterBy('{$this->getColumnForParameter('scope_column')->getPhpName()}', \$this->{$scopeGetter}())";
410
        }
411
        // watch out: some of the columns may be hidden by the soft_delete behavior
412
        if ($this->table->hasBehavior('soft_delete')) {
413
            $script .= "
414
        ->includeDeleted()";
415
        }
416
        $script .= "
417
    ;
418
419
    if (!\$alreadyExists) {
420
        \$count = \$query->count();
421
        if (\$count > 0) {
422
            return \$this->makeSlugUnique(\$slug, \$separator, true);
423
        }
424
425
        return \$slug2;
426
    }
427
428
    // Already exists
429
    \$object = \$query
430
        ->addDescendingOrderByColumn('LENGTH(" . $this->getColumnForParameter('slug_column')->getName() . ")')
431
        ->addDescendingOrderByColumn('" . $this->getColumnForParameter('slug_column')->getName() . "')
432
    ->findOne();
433
434
    // First duplicate slug
435
    if (null == \$object) {
436
        return \$slug2 . '1';
437
    }
438
439
    \$slugNum = substr(\$object->" . $getter . "(), strlen(\$slug) + 1);
440
    if ('0' === \$slugNum[0]) {
441
        \$slugNum[0] = 1;
442
    }
443
444
    return \$slug2 . (\$slugNum + 1);
445
}
446
";
447
    }
448
449
    public function queryMethods(\QueryBuilder $builder)
450
    {
451
        $this->builder = $builder;
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
452
        $script = '';
453
454
        if ($this->getParameter('slug_column') != 'slug') {
455
            $this->addFilterBySlug($script);
456
            $this->addFindOneBySlug($script);
457
        }
458
459
        return $script;
460
    }
461
462
    protected function addFilterBySlug(&$script)
463
    {
464
        $script .= "
465
/**
466
 * Filter the query on the slug column
467
 *
468
 * @param     string \$slug The value to use as filter.
469
 *
470
 * @return    " . $this->builder->getStubQueryBuilder()->getClassname() . " The current query, for fluid interface
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
471
 */
472
public function filterBySlug(\$slug)
473
{
474
    return \$this->addUsingAlias(" . $this->builder->getColumnConstant($this->getColumnForParameter('slug_column')) . ", \$slug, Criteria::EQUAL);
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
475
}
476
";
477
    }
478
479
    protected function addFindOneBySlug(&$script)
480
    {
481
        $script .= "
482
/**
483
 * Find one object based on its slug
484
 *
485
 * @param     string \$slug The value to use as filter.
486
 * @param     PropelPDO \$con The optional connection object
487
 *
488
 * @return    " . $this->builder->getStubObjectBuilder()->getClassname() . " the result, formatted by the current formatter
0 ignored issues
show
The property builder does not seem to exist. Did you mean additionalBuilders?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
489
 */
490
public function findOneBySlug(\$slug, \$con = null)
491
{
492
    return \$this->filterBySlug(\$slug)->findOne(\$con);
493
}
494
";
495
    }
496
497
    /**
498
     * @param string $string
499
     *
500
     * @return string
501
     */
502
    protected function underscore($string)
503
    {
504
        return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($string, '_', '.')));
505
    }
506
}