Passed
Pull Request — master (#3)
by Chauncey
07:29 queued 03:41
created

TemplateProperty::addChoices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
namespace Charcoal\Property;
4
5
use PDO;
6
7
use RuntimeException;
8
use InvalidArgumentException;
9
10
// From Pimple
11
use Pimple\Container;
12
13
// From 'charcoal-translator'
14
use Charcoal\Translator\Translation;
15
16
// From 'charcoal-property'
17
use Charcoal\Property\AbstractProperty;
18
use Charcoal\Property\SelectablePropertyInterface;
19
use Charcoal\Property\SelectablePropertyTrait;
20
21
/**
22
 * Template Selector Property
23
 */
24
class TemplateProperty extends AbstractProperty implements SelectablePropertyInterface
0 ignored issues
show
Bug introduced by
There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: loadMetadata, metadata, metadataIdent, setMetadata, setMetadataIdent, setMetadataLoader, setValidator, validate, validator
Loading history...
25
{
26
    use SelectablePropertyTrait;
27
28
    /**
29
     * The available selectable templates.
30
     *
31
     * @var array|null
32
     */
33
    private $availableTemplates;
34
35
    /**
36
     * @return string
37
     */
38
    public function type()
39
    {
40
        return 'template';
41
    }
42
43
    /**
44
     * Inject dependencies from a DI Container.
45
     *
46
     * @param  Container $container A dependencies container instance.
47
     * @return void
48
     */
49
    public function setDependencies(Container $container)
50
    {
51
        parent::setDependencies($container);
52
53
        if (isset($container['config']['templates'])) {
54
            $this->availableTemplates = $this->parseChoices($container['config']['templates']);
55
            $this->choices = $this->availableTemplates;
56
        }
57
    }
58
59
    /**
60
     * Set the available choices.
61
     *
62
     * @param  array $choices One or more choice structures.
63
     * @return TemplateProperty Chainable.
64
     */
65
    public function setChoices(array $choices)
66
    {
67
        unset($choices);
68
69
        $this->logger->debug(
70
            'Choices can not be set for template properties. They are auto-generated from available languages.'
71
        );
72
73
        return $this;
74
    }
75
76
    /**
77
     * Merge the available choices.
78
     *
79
     * @param  array $choices One or more choice structures.
80
     * @return TemplateProperty Chainable.
81
     */
82
    public function addChoices(array $choices)
83
    {
84
        unset($choices);
85
86
        $this->logger->debug(
87
            'Choices can not be added for template properties. They are auto-generated from available languages.'
88
        );
89
90
        return $this;
91
    }
92
93
    /**
94
     * Add a choice to the available choices.
95
     *
96
     * @param string       $choiceIdent The choice identifier (will be key / default ident).
97
     * @param string|array $choice      A string representing the choice label or a structure.
98
     * @return TemplateProperty Chainable.
99
     */
100
    public function addChoice($choiceIdent, $choice)
101
    {
102
        unset($choiceIdent, $choice);
103
104
        $this->logger->debug(
105
            'Choices can not be added for template properties. They are auto-generated from available languages.'
106
        );
107
108
        return $this;
109
    }
110
111
    /**
112
     * Format the given value for display.
113
     *
114
     * @param  mixed $val     The value to to convert for display.
115
     * @param  array $options Optional display options.
116
     * @return string
117
     */
118
    public function displayVal($val, array $options = [])
119
    {
120
        if ($val === null || $val === '') {
121
            return '';
122
        }
123
124
        /** Parse multilingual values */
125
        if ($this->l10n()) {
126
            $propertyValue = $this->l10nVal($val, $options);
127
            if ($propertyValue === null) {
128
                return '';
129
            }
130
        } elseif ($val instanceof Translation) {
131
            $propertyValue = (string)$val;
132
        } else {
133
            $propertyValue = $val;
134
        }
135
136
        $separator = $this->multipleSeparator();
137
138
        /** Parse multiple values / ensure they are of array type. */
139
        if ($this->multiple()) {
140
            if (!is_array($propertyValue)) {
141
                $propertyValue = explode($separator, $propertyValue);
142
            }
143
        }
144
145
        if ($separator === ',') {
146
            $separator = ', ';
147
        }
148
149
        if (is_array($propertyValue)) {
150
            foreach ($propertyValue as &$value) {
151 View Code Duplication
                if (is_string($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                    $value = $this->choiceLabel($value);
153
                    if (!is_string($value)) {
154
                        $value = $this->l10nVal($value, $options);
155
                    }
156
                }
157
            }
158
            $propertyValue = implode($separator, $propertyValue);
159 View Code Duplication
        } elseif (is_string($propertyValue)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
            $propertyValue = $this->choiceLabel($propertyValue);
161
            if (!is_string($propertyValue)) {
162
                $propertyValue = $this->l10nVal($propertyValue, $options);
163
            }
164
        }
165
166
        return $propertyValue;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $propertyValue; (string|null|object|integer|double|boolean) is incompatible with the return type declared by the interface Charcoal\Property\PropertyInterface::displayVal of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
167
    }
168
169
    /**
170
     * Retrieve the selected template's FQCN.
171
     *
172
     * @return string
173
     */
174
    public function __toString()
175
    {
176
        $val = $this->val();
177
        if ($this->hasChoice($val)) {
178
            $choice = $this->choice($val);
179
            $keys   = [ 'controller', 'template', 'class' ];
180
            foreach ($keys as $key) {
181
                if (isset($choice[$key])) {
182
                    return $choice[$key];
183
                }
184
            }
185
        }
186
187
        return '';
188
    }
189
190
    /**
191
     * @return string
192
     */
193
    public function sqlExtra()
194
    {
195
        return '';
196
    }
197
198
    /**
199
     * Get the SQL type (Storage format)
200
     *
201
     * @return string The SQL type
202
     */
203
    public function sqlType()
204
    {
205
        if ($this->multiple()) {
206
            return 'TEXT';
207
        }
208
209
        return 'VARCHAR(255)';
210
    }
211
212
    /**
213
     * @return integer
214
     */
215
    public function sqlPdoType()
216
    {
217
        return PDO::PARAM_STR;
218
    }
219
}
220