Completed
Push — master ( c22fb0...9cd21e )
by Mathieu
03:08
created

RoutableTrait   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 9
Bugs 4 Features 1
Metric Value
wmc 15
c 9
b 4
f 1
lcom 1
cbo 4
dl 0
loc 162
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setSlugPattern() 0 5 1
A slugPattern() 0 10 3
A setSlug() 0 9 2
A slug() 0 4 1
B generateSlug() 0 34 6
A url() 0 4 1
A slugify() 0 51 1
1
<?php
2
3
namespace Charcoal\Object;
4
5
use \Charcoal\View\ViewableInterface;
6
use \Charcoal\Translation\TranslationString;
7
use \Charcoal\Translation\TranslationConfig;
8
9
/**
10
 * Full implementation, as Trait, of the `RoutableInterface`.
11
 */
12
trait RoutableTrait
13
{
14
    /**
15
     * @var string
16
     */
17
    private $slugPattern = '';
18
19
    /**
20
     * @var string $slug
21
     */
22
    private $slug;
23
24
    /**
25
     * @param mixed $pattern The slug pattern.
26
     * @return RoutableInterface Chainable
27
     */
28
    public function setSlugPattern($pattern)
29
    {
30
        $this->slugPattern = new TranslationString($pattern);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Charcoal\Translatio...slationString($pattern) of type object<Charcoal\Translation\TranslationString> is incompatible with the declared type string of property $slugPattern.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
31
        return $this;
32
    }
33
34
    /**
35
     * @return TranslationString
36
     */
37
    public function slugPattern()
38
    {
39
        if (!$this->slugPattern) {
40
            $metadata = $this->metadata();
0 ignored issues
show
Bug introduced by
It seems like metadata() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
41
            $slugPattern = isset($metadata['slug_pattern']) ? $metadata['slug_pattern'] : '';
42
            $this->setSlugPattern($slugPattern);
43
        }
44
45
        return $this->slugPattern;
46
    }
47
48
    /**
49
     * @param mixed $slug The slug.
50
     * @return RoutableInterface Chainable
51
     */
52
    public function setSlug($slug)
53
    {
54
        $this->slug = new TranslationString($slug);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Charcoal\Translation\TranslationString($slug) of type object<Charcoal\Translation\TranslationString> is incompatible with the declared type string of property $slug.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
55
        $patterns = $this->slug->all();
56
        foreach ($patterns as $lang => $pattern) {
57
            $this->slug[$lang] = $this->slugify($this->slug[$lang]);
58
        }
59
        return $this;
60
    }
61
62
    /**
63
     * @return TranslationString
64
     */
65
    public function slug()
66
    {
67
        return $this->slug;
68
    }
69
70
    /**
71
     * Generate a URL slug from the object's URL slug pattern.
72
     *
73
     * @return TranslationString
74
     */
75
    public function generateSlug()
76
    {
77
        $patterns = $this->slugPattern();
78
        $patterns = $patterns->all();
79
        $slug = new TranslationString();
80
81
        $translator = TranslationConfig::instance();
82
83
        $origLang = $translator->currentLanguage();
84
        foreach ($patterns as $lang => $pattern) {
85
            $translator->setCurrentLanguage($lang);
86
            if ($this instanceof ViewableInterface && $this->view() !== null) {
87
                $slug[$lang] = $this->view()->render($pattern, $this->viewController());
88
            } else {
89
                $obj = $this;
90
91
                $cb = function ($matches) use ($obj) {
92
                    $method = trim($matches[1]);
93
                    if (method_exists($obj, $method)) {
94
                        return call_user_func([$obj, $method]);
95
                    } elseif (isset($obj[$method])) {
96
                        return $obj[$method];
97
                    } else {
98
                        return '';
99
                    }
100
                };
101
                $slug[$lang] = preg_replace_callback('~{{(.*?)}}~i', $cb, $pattern);
102
            }
103
            $slug[$lang] = $this->slugify($slug[$lang]);
104
        }
105
        $translator->setCurrentLanguage($origLang);
106
107
        return $slug;
108
    }
109
110
    /**
111
     * @return string
112
     */
113
    public function url()
114
    {
115
        return (string)$this->slug();
116
    }
117
118
    /**
119
     * @param string $str The string to slugify.
120
     * @return string The slugified string.
121
     */
122
    public function slugify($str)
123
    {
124
        // Character options
125
        $separator = '_';
126
        $punctuation_modifier = $separator;
0 ignored issues
show
Unused Code introduced by
$punctuation_modifier 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...
127
128
        // Punctuation
129
        $punctuation_characters = ['&', '%', '?', ')', '(', '\\', '"', "'", ':', '#', '.', ',', ';', '!'];
130
131
        // Unescaped HTML characters string
132
        $unescaped_html_characters = '/&(raquo|laquo|rsaquo|lsaquo|rdquo|ldquo|rsquo|lsquo|hellip|amp|nbsp|quot|ordf|ordm);/';
133
134
        $separator = '-';
135
136
        $slug = preg_replace('/[^\p{L}\s]/u', '-', $str);
137
138
        $slug = mb_strtolower($slug, 'UTF-8');
139
140
        // Strip HTML
141
        $slug = strip_tags($slug);
142
143
        // Strip Whitespace
144
        $slug = trim($slug);
145
146
        // Remove diacritics
147
        $slug = preg_replace('/&([a-zA-Z])(uml|acute|grave|circ|tilde|cedil|ring);/', '$1', htmlentities($slug, ENT_COMPAT, 'UTF-8'));
148
149
        // Remove unescaped HTML characters
150
        $slug = preg_replace($unescaped_html_characters, '', $slug);
151
152
        // Get rid of punctuation
153
        $slug = str_replace($punctuation_characters, $separator, $slug);
154
155
        // Post-cleanup, get rid of spaces, repeating dash symbols symbols and surround whitespace/separators
156
        $slug = trim($slug);
157
158
        // Replace whitespace by seperator
159
        $slug = preg_replace('/\s+/', $separator, $slug);
160
161
        // Squeeze multiple dashes or underscores
162
        $slug = preg_replace('/[-_]{2,}/', '-', $slug);
163
164
        // Strip leading and trailing dashes or underscores
165
        $slug = trim($slug, '-_');
166
167
        // Finally, remove all whitespace
168
        $slug = preg_replace('/[_]+/', $separator, $slug);
169
        //$slug = str_replace('_', $separator, $slug);
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
170
171
        return $slug;
172
    }
173
}
174