Completed
Push — master ( 79d213...eeff33 )
by Kamil
23:15
created

ThemeSynchronizer::removeAbandonedThemes()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 20
rs 9.2
cc 4
eloc 12
nc 4
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Bundle\ThemeBundle\Synchronizer;
13
14
use Sylius\Bundle\ThemeBundle\Loader\ThemeLoaderInterface;
15
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
16
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
17
18
/**
19
 * @author Kamil Kokot <[email protected]>
20
 */
21
final class ThemeSynchronizer implements ThemeSynchronizerInterface
22
{
23
    /**
24
     * @var ThemeLoaderInterface
25
     */
26
    private $themeLoader;
27
28
    /**
29
     * @var ThemeRepositoryInterface
30
     */
31
    private $themeRepository;
32
33
    /**
34
     * @var ThemeMergerInterface
35
     */
36
    private $themeMerger;
37
38
    /**
39
     * @param ThemeLoaderInterface $themeLoader
40
     * @param ThemeRepositoryInterface $themeRepository
41
     * @param ThemeMergerInterface $themeMerger
42
     */
43
    public function __construct(
44
        ThemeLoaderInterface $themeLoader,
45
        ThemeRepositoryInterface $themeRepository,
46
        ThemeMergerInterface $themeMerger
47
    ) {
48
        $this->themeLoader = $themeLoader;
49
        $this->themeRepository = $themeRepository;
50
        $this->themeMerger = $themeMerger;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function synchronize()
57
    {
58
        $persistedThemes = $this->themeRepository->findAll();
59
        $loadedThemes = $this->themeLoader->load();
60
61
        $removedThemes = $this->removeAbandonedThemes($persistedThemes, $loadedThemes);
62
        $existingThemes = array_udiff(
63
            $persistedThemes,
64
            $removedThemes,
65
            function (ThemeInterface $firstTheme, ThemeInterface $secondTheme) {
66
                return (int) ($firstTheme->getName() === $secondTheme->getName());
67
            }
68
        );
69
70
        $this->updateThemes($existingThemes, $loadedThemes);
71
    }
72
73
    /**
74
     * @param ThemeInterface[] $existingThemes
75
     * @param ThemeInterface[] $loadedThemes
76
     */
77
    private function updateThemes(array $existingThemes, array $loadedThemes)
78
    {
79
        $loadedThemes = $this->ensureCohesionOfReferencedThemes($existingThemes, $loadedThemes);
80
81
        foreach ($loadedThemes as $loadedTheme) {
82
            $this->updateTheme($loadedTheme);
83
        }
84
    }
85
86
    /**
87
     * @param ThemeInterface $theme
88
     */
89
    private function updateTheme(ThemeInterface $theme)
90
    {
91
        $existingTheme = $this->themeRepository->findOneByName($theme->getName());
92
93
        if (null !== $existingTheme) {
94
            $theme = $this->themeMerger->merge($existingTheme, $theme);
95
        }
96
97
        $this->themeRepository->add($theme);
98
    }
99
100
    /**
101
     * @param ThemeInterface[] $persistedThemes
102
     * @param ThemeInterface[] $loadedThemes
103
     *
104
     * @return ThemeInterface[] Removed themes
105
     */
106
    private function removeAbandonedThemes(array $persistedThemes, array $loadedThemes)
107
    {
108
        if (0 === count($persistedThemes)) {
109
            return [];
110
        }
111
112
        $loadedThemesNames = array_map(function (ThemeInterface $theme) {
113
            return $theme->getName();
114
        }, $loadedThemes);
115
116
        $removedThemes = [];
117
        foreach ($persistedThemes as $persistedTheme) {
118
            if (!in_array($persistedTheme->getName(), $loadedThemesNames, true)) {
119
                $removedThemes[] = $persistedTheme;
120
                $this->themeRepository->remove($persistedTheme);
121
            }
122
        }
123
124
        return $removedThemes;
125
    }
126
127
    /**
128
     * Removes references to loaded themes, that exists.
129
     * Adds references to existing themes instead (the loaded ones will be merged into them).
130
     *
131
     * @param ThemeInterface[] $existingThemes
132
     * @param ThemeInterface[] $loadedThemes
133
     *
134
     * @return ThemeInterface[]
135
     */
136
    private function ensureCohesionOfReferencedThemes(array $existingThemes, array $loadedThemes)
137
    {
138
        foreach ($loadedThemes as $loadedTheme) {
139
            foreach ($loadedTheme->getParents() as $parentTheme) {
140
                $correspondingTheme = current(array_filter(
141
                    array_merge($existingThemes, $loadedThemes),
142
                    function (ThemeInterface $theme) use ($parentTheme) {
143
                        return $theme->getName() === $parentTheme->getName();
144
                    }
145
                ));
146
147
                if (null === $correspondingTheme) {
148
                    throw new SynchronizationFailedException('Cannot find a corresponding theme!');
149
                }
150
151
                $loadedTheme->removeParent($parentTheme);
152
                $loadedTheme->addParent($correspondingTheme);
153
            }
154
        }
155
156
        return $loadedThemes;
157
    }
158
}
159