Skip to content

Commit

Permalink
Make CoreBundle optional (#6096)
Browse files Browse the repository at this point in the history
* Add CoreBundle assets

* Make CoreBundle optional
  • Loading branch information
wbloszyk committed Jun 12, 2020
1 parent a0f815b commit 2fafa32
Show file tree
Hide file tree
Showing 1,449 changed files with 233,353 additions and 38 deletions.
8 changes: 5 additions & 3 deletions composer.json
Expand Up @@ -27,12 +27,13 @@
"doctrine/inflector": "^1.4 || ^2.0",
"knplabs/knp-menu-bundle": "^2.2.2",
"sonata-project/block-bundle": "^3.18",
"sonata-project/core-bundle": "^3.18.0",
"sonata-project/exporter": "^1.11.0 || ^2.0",
"sonata-project/exporter": "^1.11 || ^2.0",
"sonata-project/form-extensions": "^0.1.1 || ^1.4",
"sonata-project/twig-extensions": "^0.1.1 || ^1.3",
"symfony/asset": "^4.3",
"symfony/config": "^4.3",
"symfony/console": "^4.3",
"symfony/dependency-injection": "^4.3",
"symfony/dependency-injection": "^4.4.3",
"symfony/doctrine-bridge": "^4.3",
"symfony/event-dispatcher": "^4.3",
"symfony/event-dispatcher-contracts": "^1.1 || ^2.0",
Expand Down Expand Up @@ -60,6 +61,7 @@
"conflict": {
"doctrine/doctrine-bundle": ">=3",
"jms/di-extra-bundle": "<1.9",
"sonata-project/core-bundle": "<3.20",
"sonata-project/doctrine-extensions": "<1.1.3",
"sonata-project/media-bundle": "<3.7",
"sonata-project/user-bundle": "<3.3"
Expand Down
22 changes: 15 additions & 7 deletions src/DependencyInjection/SonataAdminExtension.php
Expand Up @@ -61,15 +61,16 @@ public function load(array $configs, ContainerBuilder $container)
}

$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('twig.xml');
$loader->load('actions.xml');
$loader->load('block.xml');
$loader->load('commands.xml');
$loader->load('core.xml');
$loader->load('event_listener.xml');
$loader->load('form_types.xml');
$loader->load('validator.xml');
$loader->load('route.xml');
$loader->load('block.xml');
$loader->load('menu.xml');
$loader->load('commands.xml');
$loader->load('actions.xml');
$loader->load('route.xml');
$loader->load('twig.xml');
$loader->load('validator.xml');

if (isset($bundles['MakerBundle'])) {
$loader->load('makers.xml');
Expand Down Expand Up @@ -324,12 +325,19 @@ private function replacePropertyAccessor(ContainerBuilder $container): void

private function configureTwigTextExtension(ContainerBuilder $container, XmlFileLoader $loader, array $config): void
{
$bundles = $container->getParameter('kernel.bundles');

$container->setParameter('sonata.admin.configuration.legacy_twig_text_extension', $config['options']['legacy_twig_text_extension']);
$loader->load('twig_string.xml');

if (false !== $config['options']['legacy_twig_text_extension']) {
if (isset($bundles['SonataCoreBundle']) && false !== $config['options']['legacy_twig_text_extension']) {
$stringExtension = $container->getDefinition('sonata.string.twig.extension');
$stringExtension->replaceArgument(0, new Reference('sonata.core.twig.extension.text'));
} elseif (isset($bundles['SonataTwigBundle']) && false !== $config['options']['legacy_twig_text_extension']) {
if ($container->getDefinition('sonata.twig.extension.deprecated_text_extension')) {
$stringExtension = $container->getDefinition('sonata.string.twig.extension');
$stringExtension->replaceArgument(0, new Reference('sonata.twig.extension.deprecated_text_extension'));
}
}
}
}
260 changes: 260 additions & 0 deletions src/EventListener/AssetsInstallCommandListener.php
@@ -0,0 +1,260 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\AdminBundle\EventListener;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* This listener extends `assets:install` command when SonataCoreBundle will be not register. Files from `Resources/private/SonataCoreBundleAssets`
* will be copy with the same result like SonataCoreBundle is register.
*
* This class should be remove when support for Bootstrap 3 will be ended or assets system will be remove in favor for encore webpack.
*/
final class AssetsInstallCommandListener
{
public const METHOD_COPY = 'copy';
public const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
public const METHOD_RELATIVE_SYMLINK = 'relative symlink';

protected static $defaultName = 'assets:install';

private $filesystem;
private $projectDir;

public function __construct(Filesystem $filesystem, ?string $projectDir = null)
{
if (null === $projectDir) {
@trigger_error(sprintf('Not passing the project directory to the constructor of %s is deprecated since Symfony 4.3 and will not be supported in 5.0.', __CLASS__), E_USER_DEPRECATED);
}

$this->filesystem = $filesystem;
$this->projectDir = $projectDir;
}

public function copySonataCoreBundleAssets(ConsoleTerminateEvent $event)
{
$command = $event->getCommand();
$application = $command->getApplication();

try {
$coreBundle = $application->getKernel()->getBundle('SonataCoreBundle');
} catch (\Exception $e) {
$coreBundle = null;
}

if ('assets:install' !== $command->getName() || null !== $coreBundle) {
return;
}

$output = $event->getOutput();

$this->execute($event->getInput(), $event->getOutput(), $application);
}

protected function execute(InputInterface $input, OutputInterface $output, Application $application): int
{
/**
* @var KernelInterface
*/
$kernel = $application->getKernel();

$targetArg = rtrim($input->getArgument('target') ?? '', '/');

if (!$targetArg) {
$targetArg = $this->getPublicDirectory($kernel->getContainer());
}

if (!is_dir($targetArg)) {
$targetArg = $kernel->getProjectDir().'/'.$targetArg;

if (!is_dir($targetArg)) {
throw new InvalidArgumentException(sprintf('The target directory "%s" does not exist.', $input->getArgument('target')));
}
}

$bundlesDir = $targetArg.'/bundles/';

$io = new SymfonyStyle($input, $output);
$io->newLine();

if ($input->getOption('relative')) {
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
$io->text('Trying to install deprecated SonataCoreBundle assets from SonataAdminBundle as <info>relative symbolic links</info>.');
} elseif ($input->getOption('symlink')) {
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
$io->text('Trying to install deprecated SonataCoreBundle assets from SonataAdminBundle as <info>absolute symbolic links</info>.');
} else {
$expectedMethod = self::METHOD_COPY;
$io->text('Installing deprecated SonataCoreBundle assets from SonataAdminBundle as <info>hard copies</info>.');
}

$io->newLine();

$copyUsed = false;
$exitCode = 0;
$validAssetDirs = [];

$bundle = $kernel->getBundle('SonataAdminBundle');
$originDir = $bundle->getPath().'/Resources/private/SonataCoreBundleAssets';

$assetDir = preg_replace('/bundle$/', '', 'sonatacore');
$targetDir = $bundlesDir.$assetDir;
$validAssetDirs[] = $assetDir;

if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$message = sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
} else {
$message = $bundle->getName();
}

try {
$this->filesystem->remove($targetDir);

if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
} else {
$method = $this->hardCopy($originDir, $targetDir);
}

if (self::METHOD_COPY === $method) {
$copyUsed = true;
}

if ($method === $expectedMethod) {
$ioMethod = 'success';
} else {
$ioMethod = 'warning';
}
} catch (\Exception $e) {
$exitCode = 1;
$ioMethod = 'error';
}

if (0 !== $exitCode) {
$io->error('Some errors occurred while installing assets.');
} else {
if ($copyUsed) {
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
}

switch ($ioMethod) {
case 'success':
case 'warning':$io->$ioMethod('All deprecated SonataCoreBundle assets from SonataAdminBundle were successfully installed.'); break;
case 'error':
default: $io->$ioMethod('No deprecated SonataCoreBundle assets from SonataAdminBundle were provided by any bundle.'); break;
}
}

return $exitCode;
}

/**
* Try to create relative symlink.
*
* Falling back to absolute symlink and finally hard copy.
*/
private function relativeSymlinkWithFallback(string $originDir, string $targetDir): string
{
try {
$this->symlink($originDir, $targetDir, true);
$method = self::METHOD_RELATIVE_SYMLINK;
} catch (IOException $e) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
}

return $method;
}

/**
* Try to create absolute symlink.
*
* Falling back to hard copy.
*/
private function absoluteSymlinkWithFallback(string $originDir, string $targetDir): string
{
try {
$this->symlink($originDir, $targetDir);
$method = self::METHOD_ABSOLUTE_SYMLINK;
} catch (IOException $e) {
// fall back to copy
$method = $this->hardCopy($originDir, $targetDir);
}

return $method;
}

/**
* Creates symbolic link.
*
* @throws IOException if link can not be created
*/
private function symlink(string $originDir, string $targetDir, bool $relative = false)
{
if ($relative) {
$this->filesystem->mkdir(\dirname($targetDir));
$originDir = $this->filesystem->makePathRelative($originDir, realpath(\dirname($targetDir)));
}
$this->filesystem->symlink($originDir, $targetDir);
if (!file_exists($targetDir)) {
throw new IOException(sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir), 0, null, $targetDir);
}
}

/**
* Copies origin to target.
*/
private function hardCopy(string $originDir, string $targetDir): string
{
$this->filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));

return self::METHOD_COPY;
}

private function getPublicDirectory(ContainerInterface $container): string
{
$defaultPublicDir = 'public';

if (null === $this->projectDir && !$container->hasParameter('kernel.project_dir')) {
return $defaultPublicDir;
}

$composerFilePath = ($this->projectDir ?? $container->getParameter('kernel.project_dir')).'/composer.json';

if (!file_exists($composerFilePath)) {
return $defaultPublicDir;
}

$composerConfig = json_decode(file_get_contents($composerFilePath), true);

if (isset($composerConfig['extra']['public-dir'])) {
return $composerConfig['extra']['public-dir'];
}

return $defaultPublicDir;
}
}
38 changes: 24 additions & 14 deletions src/Export/Exporter.php
Expand Up @@ -13,19 +13,29 @@

namespace Sonata\AdminBundle\Export;

use Sonata\CoreBundle\Exporter\Exporter as BaseExporter;
use Sonata\CoreBundle\Exporter\Exporter as CoreExporter;
use Sonata\Exporter\Exporter as BaseExporter;

@trigger_error(
'The '.__NAMESPACE__.'\Exporter class is deprecated since version 3.14 and will be removed in 4.0.'.
' Use \Sonata\Exporter\Exporter instead',
E_USER_DEPRECATED
);

/**
* NEXT_MAJOR: remove this class.
*
* @deprecated since sonata-project/admin-bundle 3.14, to be removed in 4.0.
*/
class Exporter extends BaseExporter
{
if (class_exists(CoreExporter::class)) {
/**
* NEXT_MAJOR: remove this class.
*
* @deprecated since sonata-project/admin-bundle 3.14, to be removed in 4.0.
*/
class Exporter extends CoreExporter
{
public function __construct()
{
@trigger_error(
'The '.__NAMESPACE__.'\Exporter class is deprecated since version 3.14 and will be removed in 4.0.'.
' Use \Sonata\Exporter\Exporter instead',
E_USER_DEPRECATED
);
}
}
} else {
class_alias(
BaseExporter::class,
__NAMESPACE__.'\Exporter'
);
}
2 changes: 1 addition & 1 deletion src/Form/Type/Filter/DateRangeType.php
Expand Up @@ -14,7 +14,7 @@
namespace Sonata\AdminBundle\Form\Type\Filter;

use Sonata\AdminBundle\Form\Type\Operator\DateRangeOperatorType;
use Sonata\CoreBundle\Form\Type\DateRangeType as FormDateRangeType;
use Sonata\Form\Type\DateRangeType as FormDateRangeType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
Expand Down
2 changes: 1 addition & 1 deletion src/Form/Type/Filter/DateTimeRangeType.php
Expand Up @@ -14,7 +14,7 @@
namespace Sonata\AdminBundle\Form\Type\Filter;

use Sonata\AdminBundle\Form\Type\Operator\DateRangeOperatorType;
use Sonata\CoreBundle\Form\Type\DateTimeRangeType as FormDateTimeRangeType;
use Sonata\Form\Type\DateTimeRangeType as FormDateTimeRangeType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
Expand Down

0 comments on commit 2fafa32

Please sign in to comment.