Completed
Push — master ( db30e2...3405a3 )
by Paweł
08:38
created

ThemeService::installAndProcessGeneratedData()   B

Complexity

Conditions 6
Paths 48

Size

Total Lines 39
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 8.439
c 0
b 0
f 0
cc 6
eloc 25
nc 48
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Superdesk Web Publisher Core Bundle.
7
 *
8
 * Copyright 2018 Sourcefabric z.ú. and contributors.
9
 *
10
 * For the full copyright and license information, please see the
11
 * AUTHORS and LICENSE files distributed with this source code.
12
 *
13
 * @copyright 2018 Sourcefabric z.ú
14
 * @license http://www.superdesk.org/license
15
 */
16
17
namespace SWP\Bundle\CoreBundle\Theme\Service;
18
19
use SWP\Bundle\CoreBundle\Model\TenantInterface;
20
use SWP\Bundle\CoreBundle\Theme\Installer\ThemeInstallerInterface;
21
use SWP\Bundle\CoreBundle\Theme\Model\ThemeInterface;
22
use SWP\Bundle\CoreBundle\Theme\Processor\RequiredDataProcessorInterface;
23
use SWP\Bundle\CoreBundle\Theme\Repository\ReloadableThemeRepositoryInterface;
24
use SWP\Component\MultiTenancy\Context\TenantContextInterface;
25
use Sylius\Bundle\ThemeBundle\Context\ThemeContextInterface;
26
use Sylius\Bundle\ThemeBundle\Repository\ThemeRepositoryInterface;
27
use Symfony\Component\Filesystem\Filesystem;
28
29
/**
30
 * Class InstallThemeService.
31
 */
32
final class ThemeService implements ThemeServiceInterface
33
{
34
    /**
35
     * @var ThemeInstallerInterface
36
     */
37
    private $themeInstaller;
38
39
    /**
40
     * @var RequiredDataProcessorInterface
41
     */
42
    private $requiredDataProcessor;
43
44
    /**
45
     * @var string
46
     */
47
    private $cacheDir;
48
49
    /**
50
     * @var TenantContextInterface
51
     */
52
    private $tenantContext;
53
54
    /**
55
     * @var ThemeRepositoryInterface
56
     */
57
    private $themeRepository;
58
59
    /**
60
     * @var ThemeContextInterface
61
     */
62
    private $themeContext;
63
64
    /**
65
     * ThemeService constructor.
66
     *
67
     * @param ThemeInstallerInterface            $themeInstaller
68
     * @param RequiredDataProcessorInterface     $requiredDataProcessor
69
     * @param string                             $cacheDir
70
     * @param TenantContextInterface             $tenantContext
71
     * @param ReloadableThemeRepositoryInterface $themeRepository
72
     * @param ThemeContextInterface              $themeContext
73
     */
74
    public function __construct(
75
        ThemeInstallerInterface $themeInstaller,
76
        RequiredDataProcessorInterface $requiredDataProcessor,
77
        string $cacheDir,
78
        TenantContextInterface $tenantContext,
79
        ReloadableThemeRepositoryInterface $themeRepository,
80
        ThemeContextInterface $themeContext
81
    ) {
82
        $this->themeInstaller = $themeInstaller;
83
        $this->requiredDataProcessor = $requiredDataProcessor;
84
        $this->cacheDir = $cacheDir;
85
        $this->tenantContext = $tenantContext;
86
        $this->themeRepository = $themeRepository;
87
        $this->themeContext = $themeContext;
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function installAndProcessGeneratedData(string $sourceDir, string $themeDir)
94
    {
95
        $messages = [];
96
        /** @var TenantInterface $tenant */
97
        $tenant = $this->tenantContext->getTenant();
98
        $backupThemeDir = $this->cacheDir.\DIRECTORY_SEPARATOR.'backup'.\DIRECTORY_SEPARATOR.'themes'.\DIRECTORY_SEPARATOR.$tenant->getCode().\DIRECTORY_SEPARATOR.\basename($themeDir).'_previous';
99
        $fileSystem = new Filesystem();
100
101
        try {
102
            if ($fileSystem->exists($themeDir)) {
103
                $fileSystem->rename($themeDir, $backupThemeDir, true);
104
            }
105
106
            $this->themeInstaller->install($sourceDir, $themeDir);
107
            $messages[] = 'Theme has been installed successfully!';
108
            $this->themeRepository->reloadThemes();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Bundle\ThemeBundl...hemeRepositoryInterface as the method reloadThemes() does only exist in the following implementations of said interface: SWP\Bundle\CoreBundle\Th...dableInMemoryRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
109
            if (file_exists($themeDir.\DIRECTORY_SEPARATOR.'theme.json')) {
110
                $themeName = json_decode(file_get_contents($themeDir.\DIRECTORY_SEPARATOR.'theme.json'), true)['name'];
111
                $tenant->setThemeName($themeName);
112
                /** @var ThemeInterface $theme */
113
                $theme = $this->themeContext->getTheme();
114
                $this->requiredDataProcessor->processTheme($theme);
115
                $messages[] = 'Required data were generated and persisted successfully';
116
            }
117
        } catch (\Exception $e) {
118
            $fileSystem->remove($themeDir);
119
            if ($fileSystem->exists($backupThemeDir)) {
120
                $fileSystem->rename($backupThemeDir, $themeDir);
121
            }
122
123
            return $e;
124
        }
125
126
        if ($fileSystem->exists($backupThemeDir)) {
127
            $fileSystem->remove($backupThemeDir);
128
        }
129
130
        return $messages;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function getDirectoriesForTheme(string $themeName): array
137
    {
138
        /** @var ThemeInterface $theme */
139
        $theme = $this->themeInstaller->getThemeFromOrganizationThemes($themeName);
140
        $sourceDir = $theme->getPath();
141
        $themeDir = $this->themeInstaller->getThemesPath().DIRECTORY_SEPARATOR.\basename($sourceDir);
142
143
        return [$sourceDir, $themeDir];
144
    }
145
}
146