Completed
Push — master ( b06472...80d940 )
by Ryan
10:54
created

Feed::getScalarSingleValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright (c) 2017 Ryan Parman <http://ryanparman.com>.
4
 * Copyright (c) 2017 Contributors.
5
 *
6
 * http://opensource.org/licenses/Apache2.0
7
 */
8
9
declare(strict_types=1);
10
11
namespace SimplePie\Type;
12
13
use DateTime;
14
use DateTimeZone;
15
use SimplePie\Configuration;
16
use SimplePie\Exception\SimplePieException;
17
use SimplePie\Mixin\LoggerTrait;
18
use SimplePie\Parser\Date as DateParser;
19
use stdClass;
20
21
/**
22
 * Represents the top-level of a feed.
23
 */
24
class Feed extends AbstractType implements TypeInterface
25
{
26
    use LoggerTrait;
27
28
    /**
29
     * The root-most node in the feed.
30
     *
31
     * @var stdClass
32
     */
33
    protected $root;
34
35
    /**
36
     * The preferred namespace alias for a given XML namespace URI. Should be
37
     * the result of a call to `SimplePie\Util\Ns`.
38
     *
39
     * @var string
40
     */
41
    protected $namespaceAlias;
42
43
    /**
44
     * The format that should be used when determining how to parse a date from a date string.
45
     *
46
     * @var string
47
     */
48
    protected $createFromFormat;
49
50
    /**
51
     * The preferred timezone to use for date output.
52
     *
53
     * @var DateTimeZone
54
     */
55
    protected $outputTimezone;
56
57
    /**
58
     * Constructs a new instance of this class.
59
     *
60
     * @param string $namespaceAlias [description]
61
     */
62
    public function __construct(string $namespaceAlias)
63
    {
64
        $this->root           = new stdClass();
65
        $this->logger         = Configuration::getLogger();
66
        $this->namespaceAlias = $namespaceAlias;
67
    }
68
69
    /**
70
     * Proxy method which forwards requests to an underlying handler.
71
     *
72
     * @param string $nodeName The name of the method being called.
73
     * @param array  $args     Any arguments passed into that method.
74
     *
75
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Node|DateTime.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
76
     *
77
     * @codingStandardsIgnoreStart
78
     *
79
     * @method \DateTime getPublished(?string $namespaceAlias = null) Indicates an instant-in-time associated with an event early in the life-cycle of the entry.
80
     * @method \DateTime getUpdated(?string $namespaceAlias = null) Indicates the most recent instant-in-time when an entry or feed was modified in a way the publisher considers significant. Therefore, not all modifications necessarily result in a changed value.
81
     * @method SimplePie\Type\Node getId(?string $namespaceAlias = null) Conveys a permanent, universally unique identifier for an entry or feed.
82
     * @method SimplePie\Type\Node getLang(?string $namespaceAlias = null) Indicates the natural language for the element and its descendents.
83
     * @method SimplePie\Type\Node getRights(?string $namespaceAlias = null) Conveys information about rights held in and over an entry or feed.
84
     * @method SimplePie\Type\Node getSubtitle(?string $namespaceAlias = null) Conveys a human-readable description or subtitle for a feed.
85
     * @method SimplePie\Type\Node getSummary(?string $namespaceAlias = null) Conveys a short summary, abstract, or excerpt of an entry.
86
     * @method SimplePie\Type\Node getTitle(?string $namespaceAlias = null) Conveys a human-readable title for an entry or feed.
87
     * @method SimplePie\Type\Generator getGenerator(?string $namespaceAlias = null) Identifies the agent used to generate a feed, for debugging and other purposes.
88
     *
89
     * @codingStandardsIgnoreEnd
90
     */
91
    public function __call(string $nodeName, array $args)
92
    {
93
        // Make sure we have *something*
94
        if (empty($args)) {
95
            $args[0] = null;
96
        }
97
98
        // Strip `get` from the start of the node name.
99
        if ('get' === \mb_substr($nodeName, 0, 3)) {
100
            $nodeName = \lcfirst(\mb_substr($nodeName, 3));
101
        }
102
103
        $nodeName = $this->getAlias($nodeName);
104
105
        return $this->getHandler($nodeName);
106
    }
107
108
    /**
109
     * Allows the user to help the date parser by providing the format of the datestamp in the feed.
110
     *
111
     * This will be passed into `DateTime::createFromFormat()` at parse-time.
112
     *
113
     * @param string $createFromFormat The format of the datestamp in the feed.
114
     *
115
     * @return self
116
     *
117
     * @see http://php.net/manual/en/datetime.createfromformat.php
118
     */
119
    public function setDateFormat(string $createFromFormat): self
120
    {
121
        $this->createFromFormat = $createFromFormat;
122
123
        return $this;
124
    }
125
126
    /**
127
     * Set the preferred output timezone.
128
     *
129
     * This calculation is performed on a _best-effort_ basis and is not guaranteed. Factors which may affect the
130
     * calculation include:
131
     *
132
     * * the version of glibc/musl that your OS relies on
133
     * * the freshness of the timestamp data your OS relies on
134
     * * the format of the datestamp inside of the feed and PHP's ability to parse it
135
     *
136
     * @param string $timezone The timezone identifier to use. Must be compatible with `DateTimeZone`. The default
137
     *                         value is `UTC`.
138
     *
139
     * @return self
140
     */
141
    public function setOutputTimezone(string $timezone = 'UTC'): self
142
    {
143
        $this->outputTimezone = $timezone;
0 ignored issues
show
Documentation Bug introduced by
It seems like $timezone of type string is incompatible with the declared type object<DateTimeZone> of property $outputTimezone.

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...
144
145
        return $this;
146
    }
147
148
    /**
149
     * Retrieves nodes that are simple scalars, and there are only one allowed value.
150
     *
151
     * @param string      $nodeName       The name of the tree node to retrieve. Available tree nodes can be viewed by
152
     *                                    looking at the response from `getRoot()`.
153
     * @param string|null $namespaceAlias The XML namespace alias to apply.
154
     *
155
     * @return Node
156
     */
157
    public function getScalarSingleValue(string $nodeName, ?string $namespaceAlias = null): Node
158
    {
159
        $alias = $namespaceAlias ?? $this->namespaceAlias;
160
161
        if (isset($this->getRoot()->{$nodeName}[$alias])) {
162
            return $this->getRoot()->{$nodeName}[$alias];
163
        }
164
165
        return new Node();
166
    }
167
168
    //--------------------------------------------------------------------------
169
    // SINGLE COMPLEX VALUES
170
171
    public function getGenerator(?string $namespaceAlias = null): Generator
172
    {
173
        $alias = $namespaceAlias ?? $this->namespaceAlias;
174
175
        if (isset($this->getRoot()->generator[$alias])) {
176
            return $this->getRoot()->generator[$alias];
177
        }
178
179
        return new Generator();
180
    }
181
182
    //--------------------------------------------------------------------------
183
184
    public function getItems(): void
185
    {
186
    }
187
188
    //--------------------------------------------------------------------------
189
    // INTERNAL
190
191
    /**
192
     * Retrieve the root-most node in the feed.
193
     *
194
     * @return stdClass
195
     */
196
    public function getRoot(): stdClass
197
    {
198
        return $this->root;
199
    }
200
201
    /**
202
     * Finds the common internal alias for a given XML node.
203
     *
204
     * @param string $nodeName The name of the XML node.
205
     *
206
     * @return string
207
     */
208
    protected function getAlias(string $nodeName): string
209
    {
210
        switch ($nodeName) {
211
            case 'language':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
212
                return 'lang';
213
214
            case 'pubDate':
215
            case 'publishedDate':
216
                return 'published';
217
218
            default:
219
                return $nodeName;
220
        }
221
    }
222
223
    /**
224
     * Get the correct handler for a whitelisted XML node name.
225
     *
226
     * @param string $nodeName The name of the XML node.
227
     *
228
     * @throws SimplePieException
229
     *
230
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use Node|DateTime.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
231
     */
232
    protected function getHandler(string $nodeName)
233
    {
234
        switch ($nodeName) {
235
            case 'id':
236
            case 'lang':
237
            case 'rights':
238
            case 'subtitle':
239
            case 'summary':
240
            case 'title':
241
                return $this->getScalarSingleValue($nodeName, $args[0]);
0 ignored issues
show
Bug introduced by
The variable $args does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
242
243
            case 'published':
244
            case 'updated':
245
                return (new DateParser(
246
                    $this->getScalarSingleValue($nodeName, $args[0])->getValue(),
247
                    $this->outputTimezone,
0 ignored issues
show
Documentation introduced by
$this->outputTimezone is of type object<DateTimeZone>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
248
                    $this->createFromFormat
249
                ))->getDateTime();
250
251
            default:
252
                throw new SimplePieException(
253
                    \sprintf('%s is an unresolvable method.')
254
                );
255
        }
256
    }
257
}
258