CleanMediaCommand::execute()   B
last analyzed

Complexity

Conditions 8
Paths 3

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 46
rs 7.9337
c 0
b 0
f 0
cc 8
nc 3
nop 2
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
    public function configure(): void
64
    {
65
        $this->setName('sonata:media:clean-uploads')
66
            ->setDescription('Find orphaned files in media upload directory')
67
            ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Execute the cleanup as a dry run. This doesn\'t remove any files');
68
    }
69
70
    protected function execute(InputInterface $input, OutputInterface $output): int
71
    {
72
        $dryRun = (bool) $input->getOption('dry-run');
73
        $verbose = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
74
75
        $finder = Finder::create();
76
        $filesystem = new Filesystem();
77
        $baseDirectory = $this->filesystemLocal->getDirectory();
78
79
        $output->writeln(sprintf('<info>Scanning upload directory: %s</info>', $baseDirectory));
80
81
        foreach ($this->mediaPool->getContexts() as $contextName => $context) {
82
            if (!$filesystem->exists($baseDirectory.'/'.$contextName)) {
83
                $output->writeln(sprintf("<info>'%s' does not exist</info>", $baseDirectory.'/'.$contextName));
84
85
                continue;
86
            }
87
88
            $output->writeln(sprintf('<info>Context: %s</info>', $contextName));
89
90
            $files = $finder->files()->in($baseDirectory.'/'.$contextName);
91
92
            foreach ($files as $file) {
93
                $filename = $file->getFilename();
94
95
                if (!$this->mediaExists($filename, $contextName)) {
96
                    if ($dryRun) {
97
                        $output->writeln(sprintf("<info>'%s' is orphanend</info>", $filename));
98
                    } else {
99
                        try {
100
                            $filesystem->remove($file->getRealPath());
101
                            $output->writeln(sprintf("<info>'%s' was successfully removed</info>", $filename));
102
                        } catch (IOException $ioe) {
103
                            $output->writeln(sprintf('<error>%s</error>', $ioe->getMessage()));
104
                        }
105
                    }
106
                } elseif ($verbose) {
107
                    $output->writeln(sprintf("'%s' found", $filename));
108
                }
109
            }
110
        }
111
112
        $output->writeln('<info>done!</info>');
113
114
        return 0;
115
    }
116
117
    /**
118
     * @return string[]
119
     */
120
    private function getProviders(): array
121
    {
122
        if (!$this->providers) {
123
            $this->providers = [];
124
125
            foreach ($this->mediaPool->getProviders() as $provider) {
126
                if ($provider instanceof FileProvider) {
127
                    $this->providers[] = $provider->getName();
128
                }
129
            }
130
        }
131
132
        return $this->providers;
133
    }
134
135
    private function mediaExists(string $filename, ?string $context = null): bool
136
    {
137
        $mediaManager = $this->mediaManager;
138
139
        $fileParts = explode('_', $filename);
140
141
        if (\count($fileParts) > 1 && 'thumb' === $fileParts[0]) {
142
            return null !== $mediaManager->findOneBy([
143
                'id' => $fileParts[1],
144
                'context' => $context,
145
            ]);
146
        }
147
148
        return \count($mediaManager->findBy([
149
            'providerReference' => $filename,
150
            'providerName' => $this->getProviders(),
151
        ])) > 0;
152
    }
153
}
154