1 | <?php |
||
34 | final class AssetsInstallCommandListener |
||
35 | { |
||
36 | public const METHOD_COPY = 'copy'; |
||
37 | public const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink'; |
||
38 | public const METHOD_RELATIVE_SYMLINK = 'relative symlink'; |
||
39 | |||
40 | protected static $defaultName = 'assets:install'; |
||
41 | |||
42 | private $filesystem; |
||
43 | private $projectDir; |
||
44 | |||
45 | public function __construct(Filesystem $filesystem, string $projectDir) |
||
46 | { |
||
47 | $this->filesystem = $filesystem; |
||
48 | $this->projectDir = $projectDir; |
||
49 | } |
||
50 | |||
51 | public function copySonataCoreBundleAssets(ConsoleTerminateEvent $event) |
||
52 | { |
||
53 | $command = $event->getCommand(); |
||
54 | $application = $command->getApplication(); |
||
55 | \assert($application instanceof FrameworkApplication); |
||
56 | |||
57 | try { |
||
58 | $coreBundle = $application->getKernel()->getBundle('SonataCoreBundle'); |
||
59 | } catch (\Exception $e) { |
||
60 | $coreBundle = null; |
||
61 | } |
||
62 | |||
63 | if ('assets:install' !== $command->getName() || null !== $coreBundle) { |
||
64 | return; |
||
65 | } |
||
66 | |||
67 | $this->execute($event->getInput(), $event->getOutput(), $application); |
||
68 | } |
||
69 | |||
70 | protected function execute(InputInterface $input, OutputInterface $output, FrameworkApplication $application): int |
||
71 | { |
||
72 | /** |
||
73 | * @var KernelInterface |
||
74 | */ |
||
75 | $kernel = $application->getKernel(); |
||
76 | |||
77 | $targetArg = rtrim($input->getArgument('target') ?? '', '/'); |
||
78 | |||
79 | if (!$targetArg) { |
||
80 | $targetArg = $this->getPublicDirectory($kernel->getContainer()); |
||
81 | } |
||
82 | |||
83 | if (!is_dir($targetArg)) { |
||
84 | $targetArg = $kernel->getProjectDir().'/'.$targetArg; |
||
85 | |||
86 | if (!is_dir($targetArg)) { |
||
87 | throw new InvalidArgumentException(sprintf( |
||
88 | 'The target directory "%s" does not exist.', |
||
89 | $input->getArgument('target') |
||
90 | )); |
||
91 | } |
||
92 | } |
||
93 | |||
94 | $bundlesDir = $targetArg.'/bundles/'; |
||
95 | |||
96 | $io = new SymfonyStyle($input, $output); |
||
97 | $io->newLine(); |
||
98 | |||
99 | if ($input->getOption('relative')) { |
||
100 | $expectedMethod = self::METHOD_RELATIVE_SYMLINK; |
||
101 | $io->text('Trying to install deprecated SonataCoreBundle assets from SonataAdminBundle as <info>relative symbolic links</info>.'); |
||
102 | } elseif ($input->getOption('symlink')) { |
||
103 | $expectedMethod = self::METHOD_ABSOLUTE_SYMLINK; |
||
104 | $io->text('Trying to install deprecated SonataCoreBundle assets from SonataAdminBundle as <info>absolute symbolic links</info>.'); |
||
105 | } else { |
||
106 | $expectedMethod = self::METHOD_COPY; |
||
107 | $io->text('Installing deprecated SonataCoreBundle assets from SonataAdminBundle as <info>hard copies</info>.'); |
||
108 | } |
||
109 | |||
110 | $io->newLine(); |
||
111 | |||
112 | $copyUsed = false; |
||
113 | $exitCode = 0; |
||
114 | $validAssetDirs = []; |
||
115 | |||
116 | $bundle = $kernel->getBundle('SonataAdminBundle'); |
||
117 | $originDir = $bundle->getPath().'/Resources/private/SonataCoreBundleAssets'; |
||
118 | |||
119 | $assetDir = preg_replace('/bundle$/', '', 'sonatacore'); |
||
120 | $targetDir = $bundlesDir.$assetDir; |
||
121 | $validAssetDirs[] = $assetDir; |
||
122 | |||
123 | if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { |
||
124 | $message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir); |
||
|
|||
125 | } else { |
||
126 | $message = $bundle->getName(); |
||
127 | } |
||
128 | |||
129 | try { |
||
130 | $this->filesystem->remove($targetDir); |
||
131 | |||
132 | if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) { |
||
133 | $method = $this->relativeSymlinkWithFallback($originDir, $targetDir); |
||
134 | } elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) { |
||
135 | $method = $this->absoluteSymlinkWithFallback($originDir, $targetDir); |
||
136 | } else { |
||
137 | $method = $this->hardCopy($originDir, $targetDir); |
||
138 | } |
||
139 | |||
140 | if (self::METHOD_COPY === $method) { |
||
141 | $copyUsed = true; |
||
142 | } |
||
143 | |||
144 | if ($method === $expectedMethod) { |
||
145 | $ioMethod = 'success'; |
||
146 | } else { |
||
147 | $ioMethod = 'warning'; |
||
148 | } |
||
149 | } catch (\Exception $e) { |
||
150 | $exitCode = 1; |
||
151 | $ioMethod = 'error'; |
||
152 | } |
||
153 | |||
154 | if (0 !== $exitCode) { |
||
155 | $io->error('Some errors occurred while installing assets.'); |
||
156 | } else { |
||
157 | if ($copyUsed) { |
||
158 | $io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.'); |
||
159 | } |
||
160 | |||
161 | switch ($ioMethod) { |
||
162 | case 'success': |
||
163 | case 'warning':$io->$ioMethod('All deprecated SonataCoreBundle assets from SonataAdminBundle were successfully installed.'); break; |
||
164 | case 'error': |
||
165 | default: $io->$ioMethod('No deprecated SonataCoreBundle assets from SonataAdminBundle were provided by any bundle.'); break; |
||
166 | } |
||
167 | } |
||
168 | |||
169 | return $exitCode; |
||
170 | } |
||
171 | |||
172 | /** |
||
173 | * Try to create relative symlink. |
||
174 | * |
||
175 | * Falling back to absolute symlink and finally hard copy. |
||
176 | */ |
||
177 | private function relativeSymlinkWithFallback(string $originDir, string $targetDir): string |
||
178 | { |
||
179 | try { |
||
180 | $this->symlink($originDir, $targetDir, true); |
||
181 | $method = self::METHOD_RELATIVE_SYMLINK; |
||
182 | } catch (IOException $e) { |
||
183 | $method = $this->absoluteSymlinkWithFallback($originDir, $targetDir); |
||
184 | } |
||
185 | |||
186 | return $method; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Try to create absolute symlink. |
||
191 | * |
||
192 | * Falling back to hard copy. |
||
193 | */ |
||
194 | private function absoluteSymlinkWithFallback(string $originDir, string $targetDir): string |
||
195 | { |
||
196 | try { |
||
197 | $this->symlink($originDir, $targetDir); |
||
198 | $method = self::METHOD_ABSOLUTE_SYMLINK; |
||
199 | } catch (IOException $e) { |
||
200 | // fall back to copy |
||
201 | $method = $this->hardCopy($originDir, $targetDir); |
||
202 | } |
||
203 | |||
204 | return $method; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Creates symbolic link. |
||
209 | * |
||
210 | * @throws IOException if link can not be created |
||
211 | */ |
||
212 | private function symlink(string $originDir, string $targetDir, bool $relative = false) |
||
213 | { |
||
214 | if ($relative) { |
||
215 | $this->filesystem->mkdir(\dirname($targetDir)); |
||
216 | $originDir = $this->filesystem->makePathRelative($originDir, realpath(\dirname($targetDir))); |
||
217 | } |
||
218 | $this->filesystem->symlink($originDir, $targetDir); |
||
219 | if (!file_exists($targetDir)) { |
||
220 | throw new IOException(sprintf( |
||
221 | 'Symbolic link "%s" was created but appears to be broken.', |
||
222 | $targetDir |
||
223 | ), 0, null, $targetDir); |
||
224 | } |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * Copies origin to target. |
||
229 | */ |
||
230 | private function hardCopy(string $originDir, string $targetDir): string |
||
238 | |||
239 | private function getPublicDirectory(ContainerInterface $container): string |
||
261 | } |
||
262 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.