├── .gitignore ├── README.md ├── composer.json ├── phpunit.xml.dist ├── psalm.xml ├── src ├── Command │ └── MigrateToDatabaseCommand.php ├── DbI18nBundle.php ├── DependencyInjection │ ├── Configuration.php │ └── DbI18nExtension.php ├── Entity │ └── Translation.php ├── Interfaces │ ├── DbLoaderInterface.php │ ├── EntityInterface.php │ └── TranslationRepositoryInterface.php ├── Loader │ └── DbLoader.php ├── Repository │ └── TranslationRepository.php └── Resources │ ├── config │ ├── config.yaml │ └── db_i18n.yaml │ └── translations │ └── .gitignore └── tests ├── Kernel.php ├── Loader └── DbLoaderTest.php ├── TranslationTest.php └── doctrine.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | .phpunit.result.cache 4 | var/* 5 | tests/output 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sometimes You have to give the visual interface of i18n message CRUD for a customer. To do this, You need to have storage, which is not under version control and allowed from a form. 2 | 3 | # I18n messages stored in database 4 | 5 | With this bundle i18n messages stored in a database instead of files, then, you can implement web-interface to manage it. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | composer require creative/symfony-db-i18n-bundle 11 | ``` 12 | 13 | Bundle **has not** (yet) a flex auto-configurator. Add 14 | 15 | ```php 16 | Creative\DbI18nBundle\DbI18nBundle::class => ['all' => true], 17 | ``` 18 | 19 | to you `config/bundles.php` file, and (optional) place the `db_i18n.yaml` with configuration (see below) file to your config directory. 20 | 21 | ## Some rules: 22 | 23 | - you application service container must have aa array `locales` parameter with possible application locales. For example: 24 | ```yaml 25 | # config/services.yaml 26 | parameters: 27 | locales: [ 'ru', 'en', 'de' ] 28 | ``` 29 | - implementation of `Symfony\Contracts\Translation\TranslatorInterface` must have a `getCatalogue` method (usually, it have) for import messages from translation files to database. 30 | - You must define the default messages domain as `db_messages` in you views to use messages from database. For example: 31 | ```yaml 32 | # templates/main.html.twig 33 | {% trans_default_domain 'db_messages' %} 34 | ``` 35 | - update you database schema after install this bundle — use `bin/console doctrine:schema:update` command or make migration for this. 36 | 37 | So, now you can load messages from old translation files to the database. Command 38 | 39 | ```bash 40 | bin/console creative:db-i18n:migrate translations/messages.en.yaml 41 | ``` 42 | 43 | will import all messages from `[project root]/translations/messages.en.yaml`. You can set absolute path instead, nevermind, but file name must be compatible with Symfony localization files agreement — `..`. 44 | 45 | After (or instead of) that, make your forms/interfaces and add, change and so on with your messages. 46 | 47 | ## Defaults 48 | 49 | Default config is 50 | 51 | ```yaml 52 | # src/Resources/config/db_i18n.yaml 53 | db_i18n: 54 | entity: Creative\DbI18nBundle\Entity\Translation 55 | domain: db_messages 56 | ``` 57 | 58 | Copy this wherever you want and modify. 59 | 60 | As you can see, the default messages domain is `db_messages`. If you want to override this and store default Symfony domain `messages` in a database, don't forget to remove (or rename) you `translations/messages..[yaml|csv|xlf]` file. 61 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "creative/symfony-db-i18n-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Allow store i18n-messages in database", 5 | "keywords": ["symfony", "i18n", "translations"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Andrew Zhdanovskih", 10 | "email": "azh@crtweb.ru" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.2||>=8.0", 15 | "doctrine/common": "^2.12|^3.1", 16 | "doctrine/doctrine-bundle": "^1.8|^2.0", 17 | "doctrine/orm": "^2.7", 18 | "doctrine/persistence": "^2", 19 | "ramsey/uuid": "^3.8|^4", 20 | "ramsey/uuid-doctrine": "^1.5", 21 | "symfony/config": "^4.1|^5", 22 | "symfony/dependency-injection": "^4.1|^5", 23 | "symfony/doctrine-bridge": "^4.1|^5", 24 | "symfony/finder": "^4.1|^5", 25 | "symfony/framework-bundle": "^4.1|^5", 26 | "symfony/polyfill-mbstring": "*", 27 | "symfony/translation": "^4.1|^5", 28 | "symfony/twig-bridge": "^4.1|^5", 29 | "symfony/twig-bundle": "^4.1|^5", 30 | "twig/twig": "^2.4|^3", 31 | "symfony/yaml": "^4.1|^5" 32 | }, 33 | "require-dev": { 34 | "phpunit/phpunit": "^8.1", 35 | "symfony/console": "^4.1|^5", 36 | "symfony/css-selector": "^4.1|^5", 37 | "symfony/dom-crawler": "^4.1|^5", 38 | "symfony/phpunit-bridge": "^4.1|^5", 39 | "symfony/var-dumper": "^4.1|^5" 40 | }, 41 | "extra": { 42 | "branch-alias": { 43 | "dev-master": "0.3-dev" 44 | } 45 | }, 46 | "config": { 47 | "sort-packages": true 48 | }, 49 | "autoload": { 50 | "psr-4": { 51 | "Creative\\DbI18nBundle\\": "src" 52 | } 53 | }, 54 | "autoload-dev": { 55 | "psr-4": { 56 | "Creative\\DbI18nBundle\\Tests\\": "tests/" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | tests 22 | 23 | 24 | 25 | 26 | 27 | src 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Command/MigrateToDatabaseCommand.php: -------------------------------------------------------------------------------- 1 | messages.ru.yaml 38 | messages.ru.xlf 39 | my_awesome_translations.en.xlf 40 | EOL; 41 | 42 | private const BATCH_SIZE = 100; 43 | 44 | /** 45 | * @var string 46 | */ 47 | protected static $defaultName = 'creative:db-i18n:migrate'; 48 | 49 | /** 50 | * @var ParameterBagInterface 51 | */ 52 | private $container; 53 | 54 | /** 55 | * @var TranslatorInterface|Translator 56 | */ 57 | private $translator; 58 | 59 | /** 60 | * @var string 61 | */ 62 | private $entityClass; 63 | 64 | /** 65 | * @var ManagerRegistry 66 | */ 67 | private $doctrine; 68 | 69 | /** 70 | * @var TranslationRepositoryInterface 71 | */ 72 | private $translationEntityRepository; 73 | 74 | /** 75 | * MigrateToDatabaseCommand constructor. 76 | * 77 | * @param ParameterBagInterface $container 78 | * @param TranslatorInterface $translator 79 | * @param ManagerRegistry $doctrine 80 | * @param string|null $name 81 | */ 82 | public function __construct(ParameterBagInterface $container, TranslatorInterface $translator, ManagerRegistry $doctrine, string $name = null) 83 | { 84 | parent::__construct($name); 85 | $this->container = $container; 86 | $this->translator = $translator; 87 | $this->entityClass = $this->container->get('db_i18n.entity'); 88 | $this->doctrine = $doctrine; 89 | } 90 | 91 | /** 92 | * Configure options. 93 | */ 94 | protected function configure(): void 95 | { 96 | $this->setDescription('Load data from translation file and pass it to database') 97 | ->addArgument('source-file', InputArgument::REQUIRED, 'File to import') 98 | ->setHelp(self::HELP) 99 | ; 100 | } 101 | 102 | /** 103 | * @param InputInterface $input 104 | * @param OutputInterface $output 105 | * 106 | * @return int|void|null 107 | */ 108 | protected function execute(InputInterface $input, OutputInterface $output) 109 | { 110 | $this->translationEntityRepository = $this->doctrine->getRepository($this->entityClass); 111 | 112 | if (!method_exists($this->translator, 'getCatalogue')) { 113 | throw new RuntimeException('Translator service of application has no \'getCatalogue\' method'); 114 | } 115 | 116 | if (!$this->container->has('locales') || !is_array($this->container->get('locales'))) { 117 | throw new RuntimeException('Application container must have a \'locales\' parameter, and this parameter must be an array'); 118 | } 119 | 120 | $io = new SymfonyStyle($input, $output); 121 | $filePath = $this->locateFile($input->getArgument('source-file')); 122 | 123 | $locale = $this->getLocale(pathinfo($filePath, PATHINFO_FILENAME)); 124 | $domain = trim(str_replace($locale, '', pathinfo($filePath, PATHINFO_FILENAME)), '.'); 125 | $catalogue = $this->translator->getCatalogue($locale); 126 | 127 | $forExport = $catalogue->all($domain); 128 | $exported = $this->exportToDatabase($forExport, $locale, $this->container->get('db_i18n.domain')); 129 | 130 | $io->writeln(sprintf( 131 | 'Loaded form %s: %u messages, exported to database: %s', 132 | $filePath, 133 | count($forExport), 134 | $exported 135 | )); 136 | 137 | return 0; 138 | } 139 | 140 | /** 141 | * @param array $messages 142 | * @param string $locale 143 | * @param string $domain 144 | * 145 | * @return int 146 | */ 147 | protected function exportToDatabase(array $messages, string $locale, string $domain): int 148 | { 149 | $count = 0; 150 | $i = 0; 151 | $em = $this->doctrine->getManager(); 152 | foreach ($messages as $key => $value) { 153 | ++$count; 154 | ++$i; 155 | $em->persist($this->makeEntity($key, $value, $locale, $domain)); 156 | if ($i > self::BATCH_SIZE) { 157 | $i = 0; 158 | $em->flush(); 159 | } 160 | } 161 | $em->flush(); 162 | 163 | return $count; 164 | } 165 | 166 | /** 167 | * @param string $key 168 | * @param string $translation 169 | * @param string $locale 170 | * 171 | * @return EntityInterface 172 | */ 173 | protected function makeEntity(string $key, string $translation, string $locale, string $domain): EntityInterface 174 | { 175 | $entity = $this->checkEntityExists($locale, $key); 176 | $entity->load([ 177 | 'domain' => $domain, 178 | 'locale' => $locale, 179 | 'key' => $key, 180 | 'translation' => $translation, 181 | ]); 182 | 183 | return $entity; 184 | } 185 | 186 | /** 187 | * @param string $locale 188 | * @param string $key 189 | * 190 | * @return EntityInterface|object 191 | */ 192 | protected function checkEntityExists(string $locale, string $key): EntityInterface 193 | { 194 | $entity = $this->translationEntityRepository->findOneBy([ 195 | 'locale' => $locale, 196 | 'key' => $key, 197 | ]); 198 | 199 | if ($entity === null) { 200 | $entity = new $this->entityClass(); 201 | } 202 | 203 | return $entity; 204 | } 205 | 206 | /** 207 | * @param string $filename 208 | * 209 | * @return string 210 | */ 211 | protected function getLocale(string $filename): ?string 212 | { 213 | $locales = $this->container->get('locales'); 214 | $locale = null; 215 | foreach ($locales as $localeParam) { 216 | if (strpos($filename, $localeParam) !== false) { 217 | $locale = $localeParam; 218 | } 219 | } 220 | 221 | if ($locale === null) { 222 | throw new RuntimeException(sprintf('No one %s found in \'%s\'', implode(', ', $locales), $filename)); 223 | } 224 | 225 | return $locale; 226 | } 227 | 228 | /** 229 | * @param string $path 230 | * 231 | * @return string 232 | */ 233 | protected function locateFile(string $path): string 234 | { 235 | $realPath = null; 236 | if (strpos($path, '/') === 0) { 237 | $realPath = $path; 238 | } else { 239 | $realPath = $this->container->get('kernel.root_dir') . '/../' . $path; 240 | } 241 | 242 | if (!is_file($realPath) || !is_readable($realPath)) { 243 | throw new RuntimeException(sprintf('Unable to load %s file', $realPath)); 244 | } 245 | 246 | return $realPath; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/DbI18nBundle.php: -------------------------------------------------------------------------------- 1 | getRootNode() 29 | ->children() 30 | ->scalarNode('entity')->defaultValue('Creative\\DbI18nBundle\\Entity\\Translation')->end() 31 | ->scalarNode('domain')->defaultValue('db_messages')->end() 32 | ; 33 | 34 | return $treeBuilder; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/DependencyInjection/DbI18nExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 34 | 35 | $container->setParameter('db_i18n.entity', $config['entity']); 36 | $container->setParameter('db_i18n.domain', $config['domain']); 37 | $container->setParameter('db_i18n.root_dir', __DIR__ . '/../'); 38 | $container->setParameter('db_i18n.translation_dir', \dirname($container->getParameter('kernel.cache_dir'))); 39 | 40 | $localeNames = [$container->getParameter('kernel.default_locale')]; 41 | if ($container->hasParameter('locales') && is_array($locales = $container->getParameter('locales'))) { 42 | $localeNames = $locales; 43 | } 44 | $this->makeLocaleFiles($localeNames, $container->getParameter('db_i18n.translation_dir'), $container->getParameter('db_i18n.domain')); 45 | 46 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 47 | $loader->load('config.yaml'); 48 | } 49 | 50 | /** 51 | * @param array $locales 52 | * @param string $targetDir 53 | * @param string $domain 54 | */ 55 | protected function makeLocaleFiles(array $locales, string $targetDir, string $domain): void 56 | { 57 | foreach ($locales as $locale) { 58 | $path = $targetDir . '/' . $domain . '.' . $locale . '.db'; 59 | if (!is_file($path)) { 60 | touch($path); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Entity/Translation.php: -------------------------------------------------------------------------------- 1 | id; 49 | } 50 | 51 | /** 52 | * @return string|null 53 | */ 54 | public function getDomain(): ?string 55 | { 56 | return $this->domain; 57 | } 58 | 59 | /** 60 | * @param string $domain 61 | * 62 | * @return Translation 63 | */ 64 | public function setDomain(string $domain): self 65 | { 66 | $this->domain = $domain; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * @return string|null 73 | */ 74 | public function getLocale(): ?string 75 | { 76 | return $this->locale; 77 | } 78 | 79 | /** 80 | * @param string $locale 81 | * 82 | * @return Translation 83 | */ 84 | public function setLocale(string $locale): self 85 | { 86 | $this->locale = $locale; 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * @return string|null 93 | */ 94 | public function getKey(): ?string 95 | { 96 | return $this->key; 97 | } 98 | 99 | /** 100 | * @param string $key 101 | * 102 | * @return Translation 103 | */ 104 | public function setKey(string $key): self 105 | { 106 | $this->key = $key; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * @return string|null 113 | */ 114 | public function getTranslation(): ?string 115 | { 116 | return $this->translation; 117 | } 118 | 119 | /** 120 | * @param string $translation 121 | * 122 | * @return Translation 123 | */ 124 | public function setTranslation(string $translation): self 125 | { 126 | $this->translation = $translation; 127 | 128 | return $this; 129 | } 130 | 131 | public function load(array $params): EntityInterface 132 | { 133 | foreach ($params as $key => $value) { 134 | $this->{$key} = $value; 135 | } 136 | 137 | return $this; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Interfaces/DbLoaderInterface.php: -------------------------------------------------------------------------------- 1 | load([ 32 | * 'domain' => $domain, 33 | * 'locale' => $locale, 34 | * 'key' => $key, 35 | * 'translation' => $translation, 36 | * ]); 37 | * ``` 38 | * and return valid entity for store in database. 39 | * 40 | * @param array $params 41 | * 42 | * @return EntityInterface 43 | */ 44 | public function load(array $params): self; 45 | } 46 | -------------------------------------------------------------------------------- /src/Interfaces/TranslationRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | doctrine = $doctrine; 45 | $this->entityClass = $container->get('db_i18n.entity'); 46 | } 47 | 48 | /** 49 | * Loads a locale. 50 | * 51 | * @param mixed $resource A resource 52 | * @param string $locale A locale 53 | * @param string $domain The domain 54 | * 55 | * @return MessageCatalogue A MessageCatalogue instance 56 | * 57 | * @throws NotFoundResourceException when the resource cannot be found 58 | * @throws InvalidResourceException when the resource cannot be loaded 59 | */ 60 | public function load($resource, string $locale, string $domain = 'messages'): MessageCatalogue 61 | { 62 | $messages = $this->getRepository()->findByDomainAndLocale($domain, $locale); 63 | 64 | $values = array_map(static function (EntityInterface $entity) { 65 | return $entity->getTranslation(); 66 | }, $messages); 67 | 68 | $catalogue = new MessageCatalogue($locale, [ 69 | $domain => $values, 70 | ]); 71 | 72 | return $catalogue; 73 | } 74 | 75 | /** 76 | * {@inheritDoc} 77 | */ 78 | public function getRepository(): TranslationRepositoryInterface 79 | { 80 | $repository = $this->doctrine->getRepository($this->entityClass); 81 | if ($repository instanceof TranslationRepositoryInterface) { 82 | return $repository; 83 | } 84 | 85 | throw new \RuntimeException(\sprintf('Cannot load repository %s', TranslationRepositoryInterface::class)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Repository/TranslationRepository.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | public function findByDomainAndLocale(string $domain, string $locale) 39 | { 40 | return $this->createQueryBuilder('t', 't.key') 41 | ->where('t.domain = :domain') 42 | ->andWhere('t.locale = :locale') 43 | ->setParameter('domain', $domain) 44 | ->setParameter('locale', $locale) 45 | ->getQuery() 46 | ->getResult(); 47 | } 48 | 49 | /** 50 | * @param string $locale 51 | * 52 | * @return ArrayCollection 53 | */ 54 | public function findForUpdate(string $locale): ArrayCollection 55 | { 56 | $result = $this->createQueryBuilder('t') 57 | ->where('t.locale = :locale') 58 | ->setParameter('locale', $locale) 59 | ->orderBy('t.key', 'ASC') 60 | ->getQuery()->getResult(); 61 | 62 | return new ArrayCollection($result); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Resources/config/config.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | autowire: true 4 | autoconfigure: true 5 | 6 | Creative\DbI18nBundle\: 7 | resource: '../../../src' 8 | exclude: '../../../src/{Entity,Resources}' 9 | 10 | doctrine.orm.naming_strategy.underscore: 11 | class: Doctrine\ORM\Mapping\UnderscoreNamingStrategy 12 | arguments: 13 | $numberAware: true 14 | 15 | translation.loader.db: 16 | class: Creative\DbI18nBundle\Loader\DbLoader 17 | public: '%kernel.debug%' 18 | arguments: 19 | - '@parameter_bag' 20 | - '@doctrine' 21 | tags: 22 | - { name: translation.loader, alias: db } 23 | 24 | Creative\DbI18nBundle\Interfaces\TranslationRepositoryInterface: 25 | class: Creative\DbI18nBundle\Repository\TranslationRepository 26 | tags: 27 | - { name: doctrine.repository_service } 28 | 29 | Creative\DbI18nBundle\Command\MigrateToDatabaseCommand: 30 | arguments: 31 | - '@parameter_bag' 32 | - '@translator.default' 33 | - '@doctrine' 34 | tags: [ console.command ] 35 | -------------------------------------------------------------------------------- /src/Resources/config/db_i18n.yaml: -------------------------------------------------------------------------------- 1 | db_i18n: 2 | entity: Creative\DbI18nBundle\Entity\Translation 3 | domain: db_messages 4 | -------------------------------------------------------------------------------- /src/Resources/translations/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/Kernel.php: -------------------------------------------------------------------------------- 1 | load(__DIR__ . '/doctrine.yaml'); 38 | $loader->load(__DIR__ . '/../src/Resources/config', 'glob'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Loader/DbLoaderTest.php: -------------------------------------------------------------------------------- 1 | get('translation.loader.db')); 23 | } 24 | 25 | protected function setUp(): void 26 | { 27 | self::bootKernel(); 28 | $doctrine = self::$container->get('doctrine'); 29 | /** @var EntityManager $em */ 30 | $em = $doctrine->getManager(); 31 | 32 | $schemaTool = new SchemaTool($em); 33 | 34 | $schemaTool->dropSchema([$em->getClassMetadata(Translation::class)]); 35 | $schemaTool->updateSchema([$em->getClassMetadata(Translation::class)]); 36 | 37 | $item = (new Translation()) 38 | ->setDomain('db_messages') 39 | ->setKey('translatable.key') 40 | ->setLocale('en') 41 | ->setTranslation('This is a translation of key'); 42 | $doctrine = self::$container->get('doctrine'); 43 | $em = $doctrine->getManager(); 44 | $em->persist($item); 45 | $em->flush(); 46 | 47 | parent::setUp(); 48 | } 49 | 50 | public function testLoadCatalogue(): void 51 | { 52 | $service = self::$container->get('translation.loader.db'); 53 | $cat = $service->load(null, 'en', 'db_messages'); 54 | self::assertInstanceOf(MessageCatalogue::class, $cat); 55 | self::assertSame('This is a translation of key', $cat->get('translatable.key', 'db_messages')); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/TranslationTest.php: -------------------------------------------------------------------------------- 1 | entity = new Translation(); 24 | } 25 | 26 | public function testGetId() 27 | { 28 | self::assertNull($this->entity->getId()); 29 | } 30 | 31 | public function testSetDomain() 32 | { 33 | self::assertInstanceOf(Translation::class, $this->entity->setDomain('domain')); 34 | } 35 | 36 | public function testSetLocale() 37 | { 38 | self::assertInstanceOf(Translation::class, $this->entity->setLocale('ru')); 39 | } 40 | 41 | public function testGetKey() 42 | { 43 | self::assertNull($this->entity->getKey()); 44 | } 45 | 46 | public function testGetDomain() 47 | { 48 | self::assertNull($this->entity->getDomain()); 49 | $this->entity->setDomain('domain'); 50 | self::assertEquals('domain', $this->entity->getDomain()); 51 | } 52 | 53 | public function testGetTranslation() 54 | { 55 | self::assertNull($this->entity->getTranslation()); 56 | $this->entity->setTranslation('translation'); 57 | self::assertEquals('translation', $this->entity->getTranslation()); 58 | } 59 | 60 | public function testGetLocale() 61 | { 62 | self::assertNull($this->entity->getLocale()); 63 | $this->entity->setLocale('en'); 64 | self::assertEquals('en', $this->entity->getLocale()); 65 | } 66 | 67 | public function testSetTranslation() 68 | { 69 | self::assertInstanceOf(Translation::class, $this->entity->setTranslation('translation')); 70 | } 71 | 72 | public function testSetKey() 73 | { 74 | self::assertInstanceOf(Translation::class, $this->entity->setKey('key')); 75 | } 76 | 77 | public function testLoad() 78 | { 79 | $params = [ 80 | 'locale' => 'en', 81 | 'key' => 'key', 82 | 'translation' => 'translation', 83 | 'domain' => 'domain', 84 | ]; 85 | 86 | self::assertInstanceOf(Translation::class, $this->entity->load($params)); 87 | self::assertEquals('en', $this->entity->getLocale()); 88 | self::assertEquals('key', $this->entity->getKey()); 89 | self::assertEquals('translation', $this->entity->getTranslation()); 90 | self::assertEquals('domain', $this->entity->getDomain()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/doctrine.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | env(DATABASE_URL): '' 3 | 4 | doctrine: 5 | dbal: 6 | url: 'sqlite:///%kernel.cache_dir%/../../app.db' 7 | driver: 'pdo_sqlite' 8 | charset: utf8 9 | types: 10 | uuid: Ramsey\Uuid\Doctrine\UuidType 11 | orm: 12 | auto_generate_proxy_classes: true 13 | naming_strategy: doctrine.orm.naming_strategy.underscore 14 | auto_mapping: true 15 | mappings: 16 | App: 17 | is_bundle: false 18 | type: annotation 19 | dir: '%kernel.project_dir%/src/Entity' 20 | prefix: 'App\Entity' 21 | alias: App 22 | --------------------------------------------------------------------------------