Completed
Push — master ( ff8d0f...7f6228 )
by
unknown
02:25 queued 11s
created

CleanMediaCommand   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 0
Metric Value
wmc 17
lcom 2
cbo 10
dl 0
loc 128
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A configure() 0 6 1
B execute() 0 46 8
A getProviders() 0 14 4
A mediaExists() 0 18 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\MediaBundle\Command;
15
16
use Sonata\MediaBundle\Filesystem\Local;
17
use Sonata\MediaBundle\Model\MediaManagerInterface;
18
use Sonata\MediaBundle\Provider\FileProvider;
19
use Sonata\MediaBundle\Provider\MediaProviderInterface;
20
use Sonata\MediaBundle\Provider\Pool;
21
use Symfony\Component\Console\Command\Command;
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Input\InputOption;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Filesystem\Exception\IOException;
26
use Symfony\Component\Filesystem\Filesystem;
27
use Symfony\Component\Finder\Finder;
28
29
/**
30
 * @final since sonata-project/media-bundle 3.21.0
31
 */
32
class CleanMediaCommand extends Command
33
{
34
    /**
35
     * @var MediaProviderInterface[]|null
36
     */
37
    private $providers;
38
39
    /**
40
     * @var Pool
41
     */
42
    private $mediaPool;
43
44
    /**
45
     * @var Local
46
     */
47
    private $filesystemLocal;
48
49
    /**
50
     * @var MediaManagerInterface
51
     */
52
    private $mediaManager;
53
54
    public function __construct(Local $filesystemLocal, Pool $mediaPool, MediaManagerInterface $mediaManager)
55
    {
56
        parent::__construct();
57
58
        $this->filesystemLocal = $filesystemLocal;
59
        $this->mediaPool = $mediaPool;
60
        $this->mediaManager = $mediaManager;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function configure(): void
67
    {
68
        $this->setName('sonata:media:clean-uploads')
69
            ->setDescription('Find orphaned files in media upload directory')
70
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Execute the cleanup as a dry run. This doesn\'t remove any files');
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    protected function execute(InputInterface $input, OutputInterface $output): int
77
    {
78
        $dryRun = (bool) $input->getOption('dry-run');
79
        $verbose = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
80
81
        $finder = Finder::create();
82
        $filesystem = new Filesystem();
83
        $baseDirectory = $this->filesystemLocal->getDirectory();
84
85
        $output->writeln(sprintf('<info>Scanning upload directory: %s</info>', $baseDirectory));
86
87
        foreach ($this->mediaPool->getContexts() as $contextName => $context) {
88
            if (!$filesystem->exists($baseDirectory.'/'.$contextName)) {
89
                $output->writeln(sprintf("<info>'%s' does not exist</info>", $baseDirectory.'/'.$contextName));
90
91
                continue;
92
            }
93
94
            $output->writeln(sprintf('<info>Context: %s</info>', $contextName));
95
96
            $files = $finder->files()->in($baseDirectory.'/'.$contextName);
97
98
            foreach ($files as $file) {
99
                $filename = $file->getFilename();
100
101
                if (!$this->mediaExists($filename, $contextName)) {
102
                    if ($dryRun) {
103
                        $output->writeln(sprintf("<info>'%s' is orphanend</info>", $filename));
104
                    } else {
105
                        try {
106
                            $filesystem->remove($file->getRealPath());
107
                            $output->writeln(sprintf("<info>'%s' was successfully removed</info>", $filename));
108
                        } catch (IOException $ioe) {
109
                            $output->writeln(sprintf('<error>%s</error>', $ioe->getMessage()));
110
                        }
111
                    }
112
                } elseif ($verbose) {
113
                    $output->writeln(sprintf("'%s' found", $filename));
114
                }
115
            }
116
        }
117
118
        $output->writeln('<info>done!</info>');
119
120
        return 0;
121
    }
122
123
    /**
124
     * @return string[]
125
     */
126
    private function getProviders(): array
127
    {
128
        if (!$this->providers) {
129
            $this->providers = [];
130
131
            foreach ($this->mediaPool->getProviders() as $provider) {
132
                if ($provider instanceof FileProvider) {
133
                    $this->providers[] = $provider->getName();
134
                }
135
            }
136
        }
137
138
        return $this->providers;
139
    }
140
141
    private function mediaExists(string $filename, string $context = null): bool
142
    {
143
        $mediaManager = $this->mediaManager;
144
145
        $fileParts = explode('_', $filename);
146
147
        if (\count($fileParts) > 1 && 'thumb' === $fileParts[0]) {
148
            return null !== $mediaManager->findOneBy([
149
                'id' => $fileParts[1],
150
                'context' => $context,
151
            ]);
152
        }
153
154
        return \count($mediaManager->findBy([
155
            'providerReference' => $filename,
156
            'providerName' => $this->getProviders(),
157
        ])) > 0;
158
    }
159
}
160