Passed
Push — ft/urls ( 560a84...fa7ece )
by Ben
23:24 queued 11s
created

SaveUrlSlugs::saveWildcardSlug()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
1
<?php
2
3
namespace Thinktomorrow\Chief\Urls;
4
5
use Thinktomorrow\Chief\Management\Assistants\UrlAssistant;
6
use Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl;
7
8
class SaveUrlSlugs
9
{
10
    /** @var ProvidesUrl */
11
    private $model;
12
13
    private $existingRecords;
14
15 58
    public function __construct(ProvidesUrl $model)
16
    {
17 58
        $this->model = $model;
18 58
    }
19
20 58
    public function handle(array $slugs): void
21
    {
22 58
        $this->existingRecords = UrlRecord::getByModel($this->model);
23
24 58
        foreach ($slugs as $locale => $slug) {
25 57
            if (!$slug) {
26 2
                $this->deleteRecord($locale);
27 2
                continue;
28
            }
29
30 57
            $this->saveRecord($locale, $this->prependBaseUrlSegment($slug, $locale));
31
        }
32 58
    }
33
34 2
    private function deleteRecord(string $locale)
35
    {
36 2
        return $this->saveRecord($locale, null);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->saveRecord($locale, null) targeting Thinktomorrow\Chief\Urls...eUrlSlugs::saveRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
37
    }
38
39 57
    private function saveRecord(string $locale, ?string $slug)
40
    {
41
        // Existing ones for this locale?
42
        $nonRedirectsWithSameLocale = $this->existingRecords->filter(function ($record) use ($locale) {
43
            return (
44 15
                $record->locale == $locale &&
45 15
                !$record->isRedirect()
46
            );
47 57
        });
48
49
        // In the case where we have any redirects that match the given slug, we need to
50
        // remove the redirect record in favour of the newly added one.
51 57
        $this->deleteIdenticalRedirects($this->existingRecords, $locale, $slug);
52
53
        // Also delete any redirects that match this locale and slug but are related to another model
54 57
        $this->deleteIdenticalRedirects(UrlRecord::where('slug', $slug)->where('locale', $locale)->get(), $locale, $slug);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
55
56
        // If slug entry is left empty, all existing records will be deleted
57 57
        if (!$slug) {
58
            $nonRedirectsWithSameLocale->each(function ($existingRecord) {
59 2
                $existingRecord->delete();
60 2
            });
61 57
        } elseif ($nonRedirectsWithSameLocale->isEmpty()) {
62 55
            $this->createRecord($locale, $slug);
63
        } else {
64
            // Only replace the existing records that differ from the current passed slugs
65
            $nonRedirectsWithSameLocale->each(function ($existingRecord) use ($slug) {
66 13
                if ($existingRecord->slug != $slug) {
67 12
                    $existingRecord->replaceAndRedirect(['slug' => $slug]);
68
                }
69 13
            });
70
        }
71 57
    }
72
73 55
    private function createRecord($locale, $slug)
74
    {
75 55
        UrlRecord::create([
76 55
            'locale'              => $locale,
77 55
            'slug'                => $slug,
78 55
            'model_type'          => $this->model->getMorphClass(),
0 ignored issues
show
Bug introduced by
The method getMorphClass() does not exist on Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl. Since it exists in all sub-types, consider adding an abstract or default implementation to Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
            'model_type'          => $this->model->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
79 55
            'model_id'            => $this->model->id,
0 ignored issues
show
Bug introduced by
Accessing id on the interface Thinktomorrow\Chief\Urls\ProvidesUrl\ProvidesUrl suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
80
        ]);
81 55
    }
82
83
    /**
84
     * @param $existingRecords
85
     * @param $locale
86
     * @param $slug
87
     */
88 57
    private function deleteIdenticalRedirects($existingRecords, $locale, $slug): void
89
    {
90
        $existingRecords->filter(function ($record) use ($locale) {
91
            return (
92 15
                $record->locale == $locale &&
93 15
                $record->isRedirect()
94
            );
95
        })->each(function ($existingRecord) use ($slug) {
96 3
            if ($existingRecord->slug == $slug) {
97 2
                $existingRecord->delete();
98
            }
99 57
        });
100 57
    }
101
102
    /**
103
     * @param string $slug
104
     * @param $locale
105
     * @return string
106
     */
107 57
    private function prependBaseUrlSegment(string $slug, $locale): string
108
    {
109 57
        $slugWithBaseSegment = $this->model->baseUrlSegment($locale) . '/' . $slug;
110 57
        $slugWithBaseSegment = trim($slugWithBaseSegment, '/');
111
112
        // If slug with base segment is empty string, it means that the passed slug was probably a "/" character.
113
        // so we'll want to return it in case the base segment is not added.
114 57
        return $slugWithBaseSegment ?: '/';
115
    }
116
}
117