diff --git a/Catalogue/CatalogueFetcher.php b/Catalogue/CatalogueFetcher.php index 4f5c954e..4b666307 100644 --- a/Catalogue/CatalogueFetcher.php +++ b/Catalogue/CatalogueFetcher.php @@ -11,9 +11,12 @@ namespace Translation\Bundle\Catalogue; -use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader; +use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader as SymfonyTranslationLoader; use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\Reader\TranslationReaderInterface; use Translation\Bundle\Model\Configuration; +use Translation\SymfonyStorage\LegacyTranslationReader; +use Translation\SymfonyStorage\TranslationLoader; /** * Fetches catalogues from source files. This will only work with local file storage @@ -26,16 +29,20 @@ final class CatalogueFetcher { /** - * @var TranslationLoader + * @var TranslationReaderInterface */ - private $loader; + private $reader; /** - * @param TranslationLoader $loader + * @param SymfonyTranslationLoader|TranslationLoader|TranslationReaderInterface $reader */ - public function __construct(TranslationLoader $loader) + public function __construct($reader) { - $this->loader = $loader; + if (!$reader instanceof TranslationReaderInterface) { + $reader = new LegacyTranslationReader($reader); + } + + $this->reader = $reader; } /** @@ -57,7 +64,7 @@ public function getCatalogues(Configuration $config, array $locales = []) $currentCatalogue = new MessageCatalogue($locale); foreach ($dirs as $path) { if (is_dir($path)) { - $this->loader->loadMessages($path, $currentCatalogue); + $this->reader->read($path, $currentCatalogue); } } $catalogues[] = $currentCatalogue; diff --git a/Catalogue/CatalogueWriter.php b/Catalogue/CatalogueWriter.php index 59ea0aa1..52bff4c7 100644 --- a/Catalogue/CatalogueWriter.php +++ b/Catalogue/CatalogueWriter.php @@ -13,7 +13,9 @@ use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Writer\TranslationWriter; +use Symfony\Component\Translation\Writer\TranslationWriterInterface; use Translation\Bundle\Model\Configuration; +use Translation\SymfonyStorage\LegacyTranslationWriter; /** * Write catalogues back to disk. @@ -25,7 +27,7 @@ final class CatalogueWriter { /** - * @var TranslationWriter + * @var TranslationWriterInterface */ private $writer; @@ -38,10 +40,12 @@ final class CatalogueWriter * @param TranslationWriter $writer * @param string $defaultLocale */ - public function __construct( - TranslationWriter $writer, - $defaultLocale - ) { + public function __construct(TranslationWriter $writer, $defaultLocale) + { + if (!$writer instanceof TranslationWriterInterface) { + $writer = new LegacyTranslationWriter($writer); + } + $this->writer = $writer; $this->defaultLocale = $defaultLocale; } @@ -53,7 +57,7 @@ public function __construct( public function writeCatalogues(Configuration $config, array $catalogues) { foreach ($catalogues as $catalogue) { - $this->writer->writeTranslations( + $this->writer->write( $catalogue, $config->getOutputFormat(), [ diff --git a/DependencyInjection/CompilerPass/LoaderOrReaderPass.php b/DependencyInjection/CompilerPass/LoaderOrReaderPass.php new file mode 100644 index 00000000..513e13f3 --- /dev/null +++ b/DependencyInjection/CompilerPass/LoaderOrReaderPass.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\DependencyInjection\CompilerPass; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * To provide a BC layer for Symfony 2.7 to 3.3 this compiler pass + * registers an alias of whether TranslationReader or TranslationLoader + * to be able to inject it in other services. + */ +class LoaderOrReaderPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if ($container->has('translation.reader')) { + $container->setAlias('translation.loader_or_reader', 'translation.reader'); + + return; + } + + if ($container->has('translation.loader')) { + $container->setAlias('translation.loader_or_reader', 'translation.loader'); + + return; + } + } +} diff --git a/DependencyInjection/TranslationExtension.php b/DependencyInjection/TranslationExtension.php index 8aaf753f..28d11f7b 100644 --- a/DependencyInjection/TranslationExtension.php +++ b/DependencyInjection/TranslationExtension.php @@ -11,8 +11,10 @@ namespace Translation\Bundle\DependencyInjection; +use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; @@ -74,6 +76,10 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('auto_translation.yml'); $this->enableFallbackAutoTranslator($container, $config); } + + if ('test' === getenv('ENV')) { + $loader->load('services_test.yml'); + } } /** @@ -105,8 +111,9 @@ private function handleConfigNode(ContainerBuilder $container, array $config) /* * Configure storage chain service */ - $storageDefinition = new DefinitionDecorator('php_translation.storage.abstract'); + $storageDefinition = $this->createChildDefinition('php_translation.storage.abstract'); $storageDefinition->replaceArgument(2, new Reference($configurationServiceId)); + $storageDefinition->setPublic(true); $container->setDefinition('php_translation.storage.'.$name, $storageDefinition); // Add storages @@ -121,7 +128,7 @@ private function handleConfigNode(ContainerBuilder $container, array $config) continue; } - $def = new DefinitionDecorator($serviceId); + $def = $this->createChildDefinition($serviceId); $def->replaceArgument(2, [$c['output_dir']]) ->replaceArgument(3, [$c['local_file_storage_options']]) ->addTag('php_translation.storage', ['type' => 'local', 'name' => $name]); @@ -131,7 +138,7 @@ private function handleConfigNode(ContainerBuilder $container, array $config) if (null !== $first) { // Create some aliases for the default storage - $container->setAlias('php_translation.storage', 'php_translation.storage.'.$first); + $container->setAlias('php_translation.storage', new Alias('php_translation.storage.'.$first, true)); if ('default' !== $first) { $container->setAlias('php_translation.storage.default', 'php_translation.storage.'.$first); } @@ -222,4 +229,20 @@ public function getAlias() { return 'translation'; } + + /** + * To avoid BC break for Symfony 3.3+. + * + * @param $parent + * + * @return ChildDefinition|DefinitionDecorator + */ + private function createChildDefinition($parent) + { + if (class_exists('Symfony\Component\DependencyInjection\ChildDefinition')) { + return new ChildDefinition($parent); + } + + return new DefinitionDecorator($parent); + } } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 7a5d0721..69528e73 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,9 +1,11 @@ services: php_translation.catalogue_fetcher: + public: true class: Translation\Bundle\Catalogue\CatalogueFetcher - arguments: ["@translation.loader"] + arguments: ["@translation.loader_or_reader"] php_translation.catalogue_writer: + public: true class: Translation\Bundle\Catalogue\CatalogueWriter arguments: ["@translation.writer", "%php_translation.default_locale%"] @@ -13,26 +15,30 @@ services: arguments: ["@php_translation.catalogue_fetcher", "@php_translation.catalogue_writer", ~] php_translation.catalogue_manager: + public: true class: Translation\Bundle\Catalogue\CatalogueManager php_translation.extractor: class: Translation\Extractor\Extractor php_translation.configuration_manager: + public: true class: Translation\Bundle\Service\ConfigurationManager php_translation.importer: + public: true class: Translation\Bundle\Service\Importer arguments: ["@php_translation.extractor"] php_translation.cache_clearer: + public: true class: Translation\Bundle\Service\CacheClearer arguments: ["%kernel.cache_dir%", "@translator", "@filesystem"] php_translation.local_file_storage.abstract: class: Translation\SymfonyStorage\FileStorage abstract: true - arguments: ["@translation.writer", "@translation.loader", ~, []] + arguments: ["@translation.writer", "@translation.loader_or_reader", ~, []] php_translation.storage.xlf_loader: class: Translation\SymfonyStorage\Loader\XliffLoader @@ -45,5 +51,6 @@ services: - { name: translation.dumper, alias: xlf, legacy-alias: xliff } php_translation.catalogue_counter: + public: true class: Translation\Bundle\Catalogue\CatalogueCounter arguments: [] diff --git a/Resources/config/services_test.yml b/Resources/config/services_test.yml new file mode 100644 index 00000000..6dc80eae --- /dev/null +++ b/Resources/config/services_test.yml @@ -0,0 +1,16 @@ +services: + test.php_translation.edit_in_place.activator: + public: true + alias: 'php_translation.edit_in_place.activator' + + test.php_translation.extractor.php: + public: true + alias: 'php_translation.extractor.php' + + test.php_translation.extractor.twig: + public: true + alias: 'php_translation.extractor.twig' + + test.php_translation.extractor: + public: true + alias: 'php_translation.extractor' diff --git a/Tests/Functional/BundleInitializationTest.php b/Tests/Functional/BundleInitializationTest.php index 62619106..63f7a07e 100644 --- a/Tests/Functional/BundleInitializationTest.php +++ b/Tests/Functional/BundleInitializationTest.php @@ -36,12 +36,12 @@ public function testRegisterBundle() $services = [ 'php_translation.storage' => StorageService::class, - 'php_translation.extractor.twig' => TwigFileExtractor::class, - 'php_translation.extractor.php' => PHPFileExtractor::class, + 'test.php_translation.extractor.twig' => TwigFileExtractor::class, + 'test.php_translation.extractor.php' => PHPFileExtractor::class, 'php_translation.catalogue_fetcher' => CatalogueFetcher::class, 'php_translation.catalogue_writer' => CatalogueWriter::class, 'php_translation.catalogue_manager' => CatalogueManager::class, - 'php_translation.extractor' => Extractor::class, + 'test.php_translation.extractor' => Extractor::class, ]; foreach ($services as $id => $class) { diff --git a/Tests/Functional/Catalogue/CatalogueFetcherTest.php b/Tests/Functional/Catalogue/CatalogueFetcherTest.php new file mode 100644 index 00000000..e7bc5be5 --- /dev/null +++ b/Tests/Functional/Catalogue/CatalogueFetcherTest.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\Translation\MessageCatalogue; +use Translation\Bundle\Catalogue\CatalogueFetcher; +use Translation\Bundle\Model\Configuration; +use Translation\Bundle\Tests\Functional\BaseTestCase; + +class CatalogueFetcherTest extends BaseTestCase +{ + /** + * @var CatalogueFetcher + */ + private $catalogueFetcher; + + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + file_put_contents( + __DIR__.'/../app/Resources/translations/messages.sv.xlf', + <<<'XML' + + + + + + key0 + trans0 + + + + + key1 + trans1 + + + + + +XML + ); + } + + public function testFetchCatalogue() + { + $this->bootKernel(); + + $this->catalogueFetcher = $this->getContainer()->get('php_translation.catalogue_fetcher'); + + $data = self::getDefaultData(); + $data['external_translations_dirs'] = [__DIR__.'/../app/Resources/translations/']; + + $conf = new Configuration($data); + + /** @var MessageCatalogue[] $catalogues */ + $catalogues = $this->catalogueFetcher->getCatalogues($conf, ['sv']); + + $this->assertEquals('sv', $catalogues[0]->getLocale()); + } + + /** + * @return array + */ + public static function getDefaultData() + { + return [ + 'name' => 'getName', + 'locales' => ['getLocales'], + 'project_root' => 'getProjectRoot', + 'output_dir' => 'getOutputDir', + 'dirs' => ['getDirs'], + 'excluded_dirs' => ['getExcludedDirs'], + 'excluded_names' => ['getExcludedNames'], + 'external_translations_dirs' => ['getExternalTranslationsDirs'], + 'output_format' => 'getOutputFormat', + 'blacklist_domains' => ['getBlacklistDomains'], + 'whitelist_domains' => ['getWhitelistDomains'], + 'xliff_version' => ['getXliffVersion'], + ]; + } + + protected function setUp() + { + parent::setUp(); + + $this->kernel->addConfigFile(__DIR__.'/../app/config/normal_config.yml'); + } +} diff --git a/Tests/Functional/Controller/EditInPlaceTest.php b/Tests/Functional/Controller/EditInPlaceTest.php index 9a968235..9026b7c6 100644 --- a/Tests/Functional/Controller/EditInPlaceTest.php +++ b/Tests/Functional/Controller/EditInPlaceTest.php @@ -25,7 +25,7 @@ public function testActivatedTest() $request = Request::create('/foobar'); // Activate the feature - $this->getContainer()->get('php_translation.edit_in_place.activator')->activate(); + $this->getContainer()->get('test.php_translation.edit_in_place.activator')->activate(); $response = $this->kernel->handle($request); @@ -57,7 +57,7 @@ public function testIfUntranslatableLabelGetsDisabled() // Activate the feature $this->bootKernel(); - $this->getContainer()->get('php_translation.edit_in_place.activator')->activate(); + $this->getContainer()->get('test.php_translation.edit_in_place.activator')->activate(); $response = $this->kernel->handle($request); diff --git a/Tests/Unit/DependencyInjection/CompilerPass/LoaderOrReaderPassTest.php b/Tests/Unit/DependencyInjection/CompilerPass/LoaderOrReaderPassTest.php new file mode 100644 index 00000000..ea9b66f0 --- /dev/null +++ b/Tests/Unit/DependencyInjection/CompilerPass/LoaderOrReaderPassTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Unit\DependencyInjection\CompilerPass; + +use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractCompilerPassTestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Translation\Bundle\DependencyInjection\CompilerPass\LoaderOrReaderPass; + +class LoaderOrReaderPassTest extends AbstractCompilerPassTestCase +{ + protected function registerCompilerPass(ContainerBuilder $container) + { + $container->addCompilerPass(new LoaderOrReaderPass()); + } + + public function testLoaderOrReader() + { + $def = new Definition(); + $this->setDefinition('translation.reader', $def); + + $this->compile(); + + $this->assertContainerBuilderHasAlias('translation.loader_or_reader'); + } +} diff --git a/TranslationBundle.php b/TranslationBundle.php index 99f997b0..f8976c04 100644 --- a/TranslationBundle.php +++ b/TranslationBundle.php @@ -16,6 +16,7 @@ use Translation\Bundle\DependencyInjection\CompilerPass\EditInPlacePass; use Translation\Bundle\DependencyInjection\CompilerPass\ExternalTranslatorPass; use Translation\Bundle\DependencyInjection\CompilerPass\ExtractorPass; +use Translation\Bundle\DependencyInjection\CompilerPass\LoaderOrReaderPass; use Translation\Bundle\DependencyInjection\CompilerPass\StoragePass; use Translation\Bundle\DependencyInjection\CompilerPass\SymfonyProfilerPass; use Translation\Bundle\DependencyInjection\CompilerPass\ValidatorVisitorPass; @@ -33,5 +34,6 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new ExtractorPass()); $container->addCompilerPass(new StoragePass()); $container->addCompilerPass(new EditInPlacePass()); + $container->addCompilerPass(new LoaderOrReaderPass()); } } diff --git a/composer.json b/composer.json index 18130fe9..56062828 100644 --- a/composer.json +++ b/composer.json @@ -11,14 +11,14 @@ ], "require": { "php": "^5.5 || ^7.0", - "symfony/framework-bundle": "^2.7 || ^3.0", - "symfony/validator": "^2.7 || ^3.0", - "symfony/translation": "^2.7 || ^3.0", - "symfony/finder": "^2.7 || ^3.0", - "symfony/intl": "^2.7 || ^3.0", + "symfony/framework-bundle": "^2.7 || ^3.0 || ^4.0", + "symfony/validator": "^2.7 || ^3.0 || ^4.0", + "symfony/translation": "^2.7 || ^3.0 || ^4.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0", + "symfony/intl": "^2.7 || ^3.0 || ^4.0", "php-translation/common": "^0.2.1", - "php-translation/symfony-storage": "^0.3.2", + "php-translation/symfony-storage": "^0.4.0", "php-translation/extractor": "^1.2" }, "require-dev": { @@ -27,13 +27,13 @@ "php-http/curl-client": "^1.7", "php-http/message": "^1.6", "php-http/message-factory": "^1.0.2", - "symfony/console": "^2.7 || ^3.0", - "symfony/twig-bundle": "^2.7 || ^3.0", - "symfony/twig-bridge": "^2.7 || ^3.0", - "symfony/asset": "^2.7 || ^3.0", - "symfony/templating": "^2.7 || ^3.0", - "symfony/dependency-injection": "^2.7 || ^3.0", - "symfony/web-profiler-bundle": "^2.7 || ^3.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0", + "symfony/twig-bundle": "^2.7 || ^3.0 || ^4.0", + "symfony/twig-bridge": "^2.7 || ^3.0 || ^4.0", + "symfony/asset": "^2.7 || ^3.0 || ^4.0", + "symfony/templating": "^2.7 || ^3.0 || ^4.0", + "symfony/dependency-injection": "^2.7 || ^3.0 || ^4.0", + "symfony/web-profiler-bundle": "^2.7 || ^3.0 || ^4.0", "matthiasnoback/symfony-dependency-injection-test": "^1.0 || ^2.0", "guzzlehttp/psr7": "^1.4", "nyholm/nsa": "^1.1", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9ab4f64a..5a93c70c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,6 +13,10 @@ bootstrap="./vendor/autoload.php" > + + + +