Completed
Push — master ( 0842cd...0b5524 )
by ARCANEDEV
07:12
created

SitemapManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.4285
cc 1
eloc 10
nc 1
nop 4
crap 1
1
<?php namespace Arcanedev\LaravelSitemap;
2
3
use Arcanedev\LaravelSitemap\Contracts\SitemapManager as SitemapManagerContract;
4
use Arcanedev\LaravelSitemap\Contracts\SitemapStyler;
5
use Illuminate\Contracts\Cache\Repository as Cache;
6
use Illuminate\Contracts\Config\Repository as Config;
7
use Illuminate\Filesystem\Filesystem as Filesystem;
8
9
/**
10
 * Class     SitemapManager
11
 *
12
 * @package  Arcanedev\LaravelSitemap
13
 * @author   ARCANEDEV <[email protected]>
14
 */
15
class SitemapManager implements SitemapManagerContract
16
{
17
    /* ------------------------------------------------------------------------------------------------
18
     |  Properties
19
     | ------------------------------------------------------------------------------------------------
20
     */
21
    /**
22
     * @var array
23
     */
24
    protected $sitemaps = [];
25
26
    /**
27
     * @var string
28
     */
29
    protected $title = null;
30
31
    /**
32
     * @var string
33
     */
34
    protected $link = null;
35
36
    /**
37
     * @var Entities\SitemapItemCollection
38
     */
39
    protected $items;
40
41
    /**
42
     * Escaping html entities.
43
     *
44
     * @var bool
45
     */
46
    private $escaping = true;
47
48
    /**
49
     * Custom max size for limitSize()
50
     *
51
     * @var bool
52
     */
53
    protected $maxSize = null;
54
55
    /**
56
     * Enable or disable cache
57
     *
58
     * @var boolean
59
     */
60
    protected $cacheEnabled = false;
61
62
    /**
63
     * Unique cache key.
64
     *
65
     * @var string
66
     */
67
    protected $cacheKey = 'laravel-sitemap.your-key';
68
69
    /**
70
     * Cache duration, can be int or timestamp
71
     *
72
     * @var int
73
     */
74
    protected $cacheDuration = 3600;
75
76
    /**
77
     * Use limit size for big sitemaps
78
     *
79
     * @var bool
80
     */
81
    protected $useLimitSize;
82
83
    /** @var  \Illuminate\Contracts\Config\Repository */
84
    protected $config;
85
86
    /** @var  \Illuminate\Contracts\Cache\Repository */
87
    protected $cache;
88
89
    /** @var  \Illuminate\Filesystem\Filesystem */
90
    protected $filesystem;
91
92
    /** @var \Arcanedev\LaravelSitemap\Contracts\SitemapStyler */
93
    private $styler;
94
95
    /* ------------------------------------------------------------------------------------------------
96
     |  Constructor
97
     | ------------------------------------------------------------------------------------------------
98
     */
99
    /**
100
     * SitemapManager constructor.
101
     *
102
     * @param  \Illuminate\Contracts\Cache\Repository             $cache
103
     * @param  \Illuminate\Contracts\Config\Repository            $config
104
     * @param  \Illuminate\Filesystem\Filesystem                  $filesystem
105
     * @param  \Arcanedev\LaravelSitemap\Contracts\SitemapStyler  $styler
106
     */
107 32
    public function __construct(
108
        Cache $cache,
109
        Config $config,
110
        Filesystem $filesystem,
111
        SitemapStyler $styler
112
    ) {
113 32
        $this->cache      = $cache;
114 32
        $this->config     = $config;
115 32
        $this->filesystem = $filesystem;
116 32
        $this->styler     = $styler;
117
118 32
        $this->init();
119 32
    }
120
121 32
    private function init()
122
    {
123 32
        $this->resetItems();
124 32
        $this->resetSitemaps();
125 32
        $this->setCache(
126 32
            $this->config->get('sitemap.cache.key',      $this->cacheKey),
127 32
            $this->config->get('sitemap.cache.lifetime', $this->cacheDuration),
128 32
            $this->config->get('sitemap.cache.enabled',  $this->cacheEnabled)
129 24
        );
130 32
        $this->setUseLimitSize($this->config->get('sitemap.use-limit-size', $this->useLimitSize));
131 32
        $this->setEscaping($this->config->get('sitemap.escaping', $this->escaping));
132 32
        $this->setMaxSize($this->config->get('sitemap.max-size', $this->maxSize));
133 32
    }
134
135
    /* ------------------------------------------------------------------------------------------------
136
     |  Getters & Setters
137
     | ------------------------------------------------------------------------------------------------
138
     */
139
    /**
140
     * Get all sitemaps.
141
     *
142
     * @return array
143
     */
144
    public function getSitemaps()
145
    {
146
        return $this->sitemaps;
147
    }
148
149
    /**
150
     * Adds sitemap to $sitemaps array.
151
     *
152
     * @param  array  $sitemap
153
     *
154
     * @return self
155
     */
156
    public function setSitemaps(array $sitemap)
157
    {
158
        $this->sitemaps[] = $sitemap;
159
160
        return $this;
161
    }
162
163
    /**
164
     * Get the sitemap items.
165
     *
166
     * @return \Arcanedev\LaravelSitemap\Entities\SitemapItemCollection
167
     */
168 16
    public function getItems()
169
    {
170 16
        return $this->items;
171
    }
172
173
    /**
174
     * Get the title.
175
     *
176
     * @return string
177
     */
178 8
    public function getTitle()
179
    {
180 8
        return $this->title;
181
    }
182
183
    /**
184
     * Set the title.
185
     *
186
     * @param  string  $title
187
     *
188
     * @return self
189
     */
190 8
    public function setTitle($title)
191
    {
192 8
        $this->title = $title;
193
194 8
        return $this;
195
    }
196
197
    /**
198
     * Get the link.
199
     *
200
     * @return string
201
     */
202 8
    public function getLink()
203
    {
204 8
        return $this->link;
205
    }
206
207
    /**
208
     * Sets $link value.
209
     *
210
     * @param  string  $link
211
     *
212
     * @return self
213
     */
214 8
    public function setLink($link)
215
    {
216 8
        $this->link = $link;
217
218 8
        return $this;
219
    }
220
221
    /**
222
     * Get the sitemap styles location.
223
     *
224
     * @return string
225
     */
226 8
    public function getStyleLocation()
227
    {
228 8
        return $this->styler->getLocation();
229
    }
230
231
    /**
232
     * Set the sitemap styles location.
233
     *
234
     * @param  string  $location
235
     *
236
     * @return self
237
     */
238 8
    public function setStyleLocation($location)
239
    {
240 8
        $this->styler->setLocation($location);
241
242 8
        return $this;
243
    }
244
245
    /**
246
     * Get the escaping value.
247
     *
248
     * @return bool
249
     */
250 24
    public function isEscaped()
251
    {
252 24
        return $this->escaping;
253
    }
254
255
    /**
256
     * Set the escaping value.
257
     *
258
     * @param  bool  $escape
259
     *
260
     * @return self
261
     */
262 32
    public function setEscaping($escape)
263
    {
264 32
        $this->escaping = (bool) $escape;
265
266 32
        return $this;
267
    }
268
269
    /**
270
     * Get the max size value.
271
     *
272
     * @return int
273
     */
274 8
    public function getMaxSize()
275
    {
276 8
        return $this->maxSize;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->maxSize; (boolean) is incompatible with the return type declared by the interface Arcanedev\LaravelSitemap...emapManager::getMaxSize of type integer.

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...
277
    }
278
279
    /**
280
     * Set the max size value.
281
     *
282
     * @param  int  $maxSize
283
     *
284
     * @return self
285
     */
286 32
    public function setMaxSize($maxSize)
287
    {
288 32
        $this->maxSize = $maxSize;
0 ignored issues
show
Documentation Bug introduced by
The property $maxSize was declared of type boolean, but $maxSize is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
289
290 32
        return $this;
291
    }
292
293
    /**
294
     * Set cache options.
295
     *
296
     * @param  string|null                        $key
297
     * @param  \Carbon\Carbon|\Datetime|int|null  $duration
298
     * @param  bool                               $useCache
299
     */
300 32
    public function setCache($key = null, $duration = null, $useCache = true)
301
    {
302 32
        $this->setCacheEnabled($useCache);
303 32
        $this->setCacheKey($key);
304 32
        $this->setCacheDuration($duration);
0 ignored issues
show
Bug introduced by
It seems like $duration defined by parameter $duration on line 300 can also be of type null or object<DateTime>; however, Arcanedev\LaravelSitemap...ger::setCacheDuration() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
305 32
    }
306
307
    /**
308
     * Get the cache enabled value.
309
     *
310
     * @return bool
311
     */
312 8
    public function isCacheEnabled()
313
    {
314 8
        return $this->cacheEnabled;
315
    }
316
317
    /**
318
     * Set the cache enabled value.
319
     *
320
     * @param  bool  $cacheEnabled
321
     *
322
     * @return self
323
     */
324 32
    public function setCacheEnabled($cacheEnabled)
325
    {
326 32
        $this->cacheEnabled = $cacheEnabled;
327
328 32
        return $this;
329
    }
330
331
    /**
332
     * Get the cache key value.
333
     *
334
     * @return string
335
     */
336 8
    public function getCacheKey()
337
    {
338 8
        return $this->cacheKey;
339
    }
340
341
    /**
342
     * Set the cache key value.
343
     *
344
     * @param  string  $key
345
     *
346
     * @return self
347
     */
348 32
    public function setCacheKey($key)
349
    {
350 32
        if ( ! is_null($key)) {
351 32
            $this->cacheKey = $key;
352 24
        }
353
354 32
        return $this;
355
    }
356
357
    /**
358
     * Get the cache duration value.
359
     *
360
     * @return int
361
     */
362 8
    public function getCacheDuration()
363
    {
364 8
        return $this->cacheDuration;
365
    }
366
367
    /**
368
     * Set cache duration value.
369
     *
370
     * @param  int  $duration
371
     *
372
     * @return self
373
     */
374 32
    public function setCacheDuration($duration)
375
    {
376 32
        if ( ! is_null($duration)) {
377 32
            $this->cacheDuration = $duration;
378 24
        }
379
380 32
        return $this;
381
    }
382
383
    /**
384
     * Checks if content is cached.
385
     *
386
     * @return bool
387
     */
388
    public function isCached()
389
    {
390
        return $this->isCacheEnabled() && $this->cache->has($this->getCacheKey());
391
    }
392
393
    /**
394
     * Get the use limit size value.
395
     *
396
     * @return bool
397
     */
398 8
    public function getUseLimitSize()
399
    {
400 8
        return $this->useLimitSize;
401
    }
402
403
    /**
404
     * Set the use limit size value.
405
     *
406
     * @param  bool  $useLimitSize
407
     *
408
     * @return self
409
     */
410 32
    public function setUseLimitSize($useLimitSize)
411
    {
412 32
        $this->useLimitSize = (bool) $useLimitSize;
413
414 32
        return $this;
415
    }
416
417
    /**
418
     * Limit size of $items array to 50000 elements (1000 for google-news).
419
     *
420
     * @param  int  $max
421
     *
422
     * @return $this
423
     */
424
    public function limitSize($max = 50000)
425
    {
426
        $this->items = $this->items->slice(0, $max);
427
428
        return $this;
429
    }
430
431
    /**
432
     * Get the use styles value.
433
     *
434
     * @return bool
435
     */
436 8
    public function getUseStyles()
437
    {
438 8
        return $this->styler->isEnabled();
439
    }
440
441
    /**
442
     * Set the use styles value.
443
     *
444
     * @param  bool  $useStyles
445
     *
446
     * @return self
447
     */
448 8
    public function setUseStyles($useStyles)
449
    {
450 8
        $this->styler->setEnabled($useStyles);
451
452 8
        return $this;
453
    }
454
455
    /* ------------------------------------------------------------------------------------------------
456
     |  Main Functions
457
     | ------------------------------------------------------------------------------------------------
458
     */
459
    /**
460
     * Add new sitemap item to $items array.
461
     *
462
     * @param  string       $loc
463
     * @param  string|null  $lastmod
464
     * @param  string|null  $priority
465
     * @param  string|null  $freq
466
     * @param  array        $images
467
     * @param  string|null  $title
468
     * @param  array        $translations
469
     * @param  array        $videos
470
     * @param  array        $googlenews
471
     * @param  array        $alternates
472
     */
473 8
    public function add(
474
        $loc, $lastmod = null, $priority = null, $freq = null, $images = [], $title = null,
475
        $translations = [], $videos = [], $googlenews = [], $alternates = []
476
    ) {
477 8
        $this->addItem(compact(
478 8
            'loc', 'lastmod', 'priority', 'freq', 'images', 'title',
479 8
            'translations', 'videos', 'googlenews', 'alternates'
480 6
        ));
481 8
    }
482
483
    /**
484
     * Add a new sitemap item.
485
     *
486
     * @param  array  $params
487
     */
488 16
    public function addItem($params = [])
489
    {
490 16
        $this->items->addItem($params, $this->isEscaped());
491 16
    }
492
493
    /**
494
     * Add multiple sitemap items.
495
     *
496
     * @param  array  $items
497
     */
498 8
    public function addItems(array $items)
499
    {
500 8
        foreach ($items as $item) { $this->addItem($item); }
501 8
    }
502
503
    /**
504
     * Add new sitemap to $sitemaps array.
505
     *
506
     * @param  string       $loc
507
     * @param  string|null  $lastmod
508
     */
509
    public function addSitemap($loc, $lastmod = null)
510
    {
511
        $this->setSitemaps(compact('loc', 'lastmod'));
512
    }
513
514
    /**
515
     * Returns document with all sitemap items from $items array.
516
     *
517
     * @param  string  $format  (options: xml, html, txt, ror-rss, ror-rdf, google-news)
518
     * @param  string  $style   (path to custom xls style like '/styles/xsl/xml-sitemap.xsl')
519
     *
520
     * @return \Symfony\Component\HttpFoundation\Response|\Illuminate\Contracts\Routing\ResponseFactory|array
521
     */
522
    public function render($format = 'xml', $style = null)
523
    {
524
        // limit size of sitemap
525
        if ($this->getMaxSize() > 0 && count($this->getItems()) > $this->getMaxSize())
526
            $this->limitSize($this->getMaxSize());
0 ignored issues
show
Documentation introduced by
$this->getMaxSize() is of type boolean, but the function expects a integer.

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...
527
        elseif ($format === SitemapStyler::GOOGLE_NEWS_FORMAT && count($this->getItems()) > 1000)
528
            $this->limitSize(1000);
529
        elseif ($format !== SitemapStyler::GOOGLE_NEWS_FORMAT && count($this->getItems()) > 50000)
530
            $this->limitSize();
531
532
        $data = $this->generate($format, $style);
533
534
        return $format === 'html'
535
            ? $data['content']
536
            : response($data['content'], 200, $data['headers']);
537
    }
538
539
    /**
540
     * Generates document with all sitemap items from $items array.
541
     *
542
     * @param  string       $format  (options: xml, html, txt, ror-rss, ror-rdf, sitemapindex, google-news)
543
     * @param  string|null  $style   (path to custom xls style like '/styles/xsl/xml-sitemap.xsl')
544
     *
545
     * @return array
546
     */
547
    public function generate($format = 'xml', $style = null)
548
    {
549
        // check if caching is enabled, there is a cached content and its duration isn't expired
550
        if ($this->isCached()) {
551
            $cached = $this->cache->get($this->getCacheKey());
552
            ($format === SitemapStyler::SITEMAPINDEX_FORMAT)
553
                ? $this->resetSitemaps($cached)
554
                : $this->resetItems($cached);
555
        }
556
        elseif ($this->isCacheEnabled()) {
557
            $this->cache->put(
558
                $this->getCacheKey(),
559
                $format === SitemapStyler::SITEMAPINDEX_FORMAT ? $this->getSitemaps() : $this->getItems(),
560
                $this->getCacheDuration()
561
            );
562
        }
563
564
        if ( ! $this->getLink())
565
            $this->setLink($this->config->get('app.url'));
566
567
        if ( ! $this->getTitle())
568
            $this->setTitle('SitemapManager for ' . $this->getLink());
569
570
        // check if styles are enabled
571
        $data = [
572
            'style' => $this->styler->get($format, $style),
573
        ];
574
575
        if ($format === SitemapStyler::SITEMAPINDEX_FORMAT) {
576
            $data['sitemaps'] = $this->getSitemaps();
577
        }
578
        else {
579
            $data['items']    = $this->getItems();
580
        }
581
582
        if (in_array($format, ['ror-rss', 'ror-rdf', 'html'])) {
583
            $data['channel'] = [
584
                'title' => $this->getTitle(),
585
                'link'  => $this->getLink(),
586
            ];
587
        }
588
589
        $contentTypes = [
590
            'ror-rss'      => 'text/rss+xml; charset=utf-8',
591
            'ror-rdf'      => 'text/rdf+xml; charset=utf-8',
592
            'html'         => 'text/html',
593
            'txt'          => 'text/plain',
594
            'sitemapindex' => 'text/xml; charset=utf-8',
595
        ];
596
597
        return [
598
            'content' => view("sitemap::$format", $data)->render(),
599
            'headers' => [
600
                'Content-type' => array_get($contentTypes, $format, 'text/xml; charset=utf-8')
601
            ],
602
        ];
603
    }
604
605
    /**
606
     * Generate sitemap and store it to a file.
607
     *
608
     * @param  string  $format    (options: xml, html, txt, ror-rss, ror-rdf, sitemapindex, google-news)
609
     * @param  string  $filename  (without file extension, may be a path like 'sitemaps/sitemap1' but must exist)
610
     * @param  string  $path      (path to store sitemap like '/www/site/public')
611
     * @param  string  $style     (path to custom xls style like '/styles/xsl/xml-sitemap.xsl')
612
     *
613
     * @return bool
614
     */
615
    public function store($format = 'xml', $filename = 'sitemap', $path = null, $style = null)
616
    {
617
        // Turn off caching for this method
618
        $this->setCacheEnabled(false);
619
620
        // Use correct file extension
621
        $extension = in_array($format, ['txt', 'html']) ? $format : 'xml';
622
623
        // Use custom size limit for sitemaps
624
        if (
625
            $this->getMaxSize() > 0 &&
626
            count($this->getItems()) >= $this->getMaxSize()
627
        ) {
628
            if ($this->getUseLimitSize()) {
629
                // limit size
630
                $this->limitSize($this->getMaxSize());
0 ignored issues
show
Documentation introduced by
$this->getMaxSize() is of type boolean, but the function expects a integer.

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...
631
            }
632
            else {
633
                // use sitemapindex and generate partial sitemaps
634
                foreach ($this->getItems()->chunk($this->getMaxSize()) as $key => $item) {
0 ignored issues
show
Documentation introduced by
$this->getMaxSize() is of type boolean, but the function expects a integer.

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...
635
                    // reset current items
636
                    $this->resetItems($item);
637
638
                    // generate new partial sitemap
639
                    $this->store($format, "$filename-$key", $path, $style);
640
641
                    // add sitemap to sitemapindex
642
                    if ( ! is_null($path))
643
                        // if using custom path generate relative urls for sitemaps in the sitemapindex
644
                        $this->addSitemap("$filename-$key.$extension");
645
                    else
646
                        // else generate full urls based on app's domain
647
                        $this->addSitemap(url("$filename-$key.$extension"));
648
                }
649
650
                $format = SitemapStyler::SITEMAPINDEX_FORMAT;
651
            }
652
        }
653
        elseif (
654
            ($format !== SitemapStyler::GOOGLE_NEWS_FORMAT && count($this->getItems()) > 50000) ||
655
            ($format === SitemapStyler::GOOGLE_NEWS_FORMAT && count($this->getItems()) > 1000)
656
        ) {
657
            ($format !== SitemapStyler::GOOGLE_NEWS_FORMAT) ? $max = 50000 : $max = 1000;
658
659
            // check if limiting size of items array is enabled
660
            if ( ! $this->getUseLimitSize()) {
661
                // use sitemapindex and generate partial sitemaps
662
                foreach ($this->getItems()->chunk($max) as $key => $item) {
663
                    // reset current items
664
                    $this->resetItems($item);
665
666
                    // generate new partial sitemap
667
                    $this->store($format, "$filename-$key", $path, $style);
668
669
                    // add sitemap to sitemapindex
670
                    if ( ! is_null($path))
671
                        // if using custom path generate relative urls for sitemaps in the sitemapindex
672
                        $this->addSitemap("$filename-$key.$extension");
673
                    else
674
                        // else generate full urls based on app's domain
675
                        $this->addSitemap(url("$filename-$key.$extension"));
676
                }
677
678
                $format = SitemapStyler::SITEMAPINDEX_FORMAT;
679
            }
680
            else {
681
                // reset items and use only most recent $max items
682
                $this->limitSize($max);
683
            }
684
        }
685
686
        $data = $this->generate($format, $style);
687
688
689
        // if custom path
690
        $file = $path == null
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $path of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
691
            ? public_path() . DS . "$filename.$extension"
692
            : $path . DS . "$filename.$extension";
693
694
        // must return something
695
        return $this->filesystem->put($file, $data['content']);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->filesystem...ile, $data['content']); (integer) is incompatible with the return type declared by the interface Arcanedev\LaravelSitemap...s\SitemapManager::store of type boolean.

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...
696
    }
697
698
    /**
699
     * Reset the sitemaps container.
700
     *
701
     * @param  array  $sitemaps
702
     *
703
     * @return self
704
     */
705 32
    public function resetSitemaps(array $sitemaps = [])
706
    {
707 32
        $this->sitemaps = $sitemaps;
708
709 32
        return $this;
710
    }
711
712
    /**
713
     * Reset the items array.
714
     *
715
     * @param  array  $items
716
     *
717
     * @return self
718
     */
719 32
    public function resetItems(array $items = [])
720
    {
721 32
        $this->items = new Entities\SitemapItemCollection($items);
722
723 32
        return $this;
724
    }
725
}
726