<?php
namespace JLaso\TranslationsApiBundle\Command;
use Doctrine\ORM\EntityManager;
use JLaso\TranslationsApiBundle\Entity\Repository\TranslationRepository;
use JLaso\TranslationsApiBundle\Entity\Translation;
use JLaso\TranslationsApiBundle\Service\ClientApiService;
use JLaso\TranslationsApiBundle\Service\ClientSocketService;
use JLaso\TranslationsApiBundle\Tools\ArrayTools;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\DialogHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\Translation\MessageCatalogueInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
use Symfony\Component\Yaml\Yaml;
/**
* Sync translations files - translations server.
*
* @author Joseluis Laso <jlaso@joseluislaso.es>
*/
class TranslationsSyncCommand extends ContainerAwareCommand
{
/** @var InputInterface */
private $input;
/** @var OutputInterface */
private $output;
/** @var EntityManager */
private $em;
/** @var ClientSocketService */
private $clientApiService;
/** @var TranslationRepository */
private $translationsRepository;
private $rootDir;
const THROWS_EXCEPTION = true;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('jlaso:translations:sync');
$this->setDescription('Sync all translations from translations server.');
$this->addOption('port', null, InputArgument::OPTIONAL, 'port');
$this->addOption('address', null, InputArgument::OPTIONAL, 'address');
$this->addOption('upload-first', null, InputArgument::OPTIONAL, '--upload-first=yes to upload our local DB to remote first of all');
$this->addOption('yml', null, InputOption::VALUE_REQUIRED, '--yml=[regenerate,blank,backup] to regenerate local .yml files from remote DB', null);
}
protected function init($server = null, $port = null)
{
/** @var EntityManager */
$this->em = $this->getContainer()->get('doctrine.orm.default_entity_manager');
/** @var ClientSocketService $clientApiService */
$clientApiService = $this->getContainer()->get('jlaso_translations.client.socket');
$this->clientApiService = $clientApiService;
$this->translationsRepository = $this->em->getRepository('TranslationsApiBundle:Translation');
$this->clientApiService->init($server, $port);
$this->rootDir = $this->getContainer()->get('kernel')->getRootDir();
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->output = $output;
$ymlOptions = array(
'regenerate' => false,
'backup' => false,
'blank' => false,
);
$yml = $this->input->getOption('yml');
if($yml){
$aux = explode(",", $yml);
if(count($aux)){
foreach($aux as $option){
$ymlOptions[$option] = true;
}
}
}
if(count($ymlOptions) != 3){
var_dump($ymlOptions);
die('Sorry, but you can use only regenerate,blank and backup with --yml option');
}
$this->init($input->getOption('address'), $input->getOption('port'));
$config = $this->getContainer()->getParameter('translations_api');
$managedLocales = $config['managed_locales'];
$this->output->writeln(PHP_EOL . '<info>*** Syncing translations ***</info>');
/**
* uploading local catalog keys (from local table) to remote server
*/
if($input->getOption('upload-first') == 'yes'){
$catalogs = $this->translationsRepository->getCatalogs();
foreach($catalogs as $catalog){
// data para enviar al servidor
$data = array();
$this->output->writeln(PHP_EOL . sprintf('<info>Processing catalog %s ...</info>', $catalog));
/** @var Translation[] $messages */
$messages = $this->translationsRepository->findBy(array('domain' => $catalog));
foreach($messages as $message){
$key = $message->getKey();
$locale = $message->getLocale();
$bundle = $message->getBundle();
$fileName = $message->getFile();
$data[$key][$locale] = array(
'message' => $message->getMessage(),
'updatedAt' => $message->getUpdatedAt()->format('c'),
'fileName' => $message->getFile(),
'bundle' => $message->getBundle(),
);
}
//print_r($data); die;
$this->output->writeln('uploadKeys("' . $catalog . '", $data)');
$result = $this->clientApiService->uploadKeys($catalog, $data);
}
}else{
/** @var DialogHelper $dialog */
$dialog = $this->getHelper('dialog');
if (!$dialog->askConfirmation(
$output,
'<question>The local DB will be erased, it is ok ?</question>',
false
)) {
die('Please, repeat the command with --force==yes in order to update remote DB with local changes');
}
}
/**
* download the remote catalogs and integrate into local table (previously truncate local table)
*/
// truncate local translations table
$this->translationsRepository->truncateTranslations();
$result = $this->clientApiService->getCatalogIndex();
if($result['result']){
$catalogs = $result['catalogs'];
}else{
die('error getting catalogs');
}
foreach($catalogs as $catalog){
$this->output->writeln(PHP_EOL . sprintf('<info>Processing catalog %s ...</info>', $catalog));
$result = $this->clientApiService->downloadKeys($catalog);
//var_dump($result); die;
file_put_contents('/tmp/' . $catalog . '.json', json_encode($result));
$bundles = $result['bundles'];
foreach($result['data'] as $key=>$data){
//$output->write("[$key]");
foreach($data as $locale=>$messageData){
//$this->output->writeln(sprintf("\t|-- key %s:%s/%s ... ", $catalog, $key, $locale));
echo '.';
$fileName = isset($messageData['fileName']) ? $messageData['fileName'] : '';
$trans = Translation::newFromArray($catalog, $key, $locale, $messageData, $bundles[$key], $fileName);
$this->em->persist($trans);
}
}
// meter las traducciones en local
}
$this->output->writeln(PHP_EOL . '<info>Flushing to DB ...</info>');
$this->em->flush();
/**
* regeneration of local .yml files if user wants
*/
/** @var DialogHelper $dialog */
$dialog = $this->getHelper('dialog');
if(($ymlOptions['regenerate']) ||
($dialog->askConfirmation($output,'<question>Do want to regenerate local .yml files ?</question>',false)))
{
$bundles = $this->translationsRepository->getBundles();
foreach($bundles as $bundle){
if(!$bundle){
continue;
}
$keys = array();
$filenames = array();
$scheme = ""; // in order to deduce filename from other keys
$translations = $this->translationsRepository->getKeysByBundle($bundle);
foreach($translations as $translation){
$locale = $translation->getLocale();
$file = $translation->getFile();
if($file && $locale && !$scheme){
$scheme = str_replace(".{$locale}.", ".%s.", $file);
break;
}
}
foreach($translations as $translation){
$locale = $translation->getLocale();
$file = $translation->getFile();
if($locale && !$file && $scheme){
$file = sprintf($scheme, $locale);
}
if($file && $locale){
if(!isset($filenames[$locale])){
$filenames[$locale] = $file;
}
$keys[$locale][$translation->getKey()] = $translation->getMessage();
}
}
foreach($filenames as $locale=>$file){
$this->output->writeln(sprintf('Generating <info>"%s"</info> ...', $file));
$subKeys = $keys[$locale];
$file = dirname($this->rootDir) . '/src/' . $file;
if($ymlOptions['blank']){
foreach($subKeys as $key=>$value){
if(!$value){
$subKeys[$key] = $key;
}
}
}
if($ymlOptions['backup'] && file_exists($file)){
copy($file, $file . '.' . date('U'));
}
file_put_contents($file, ArrayTools::prettyYamlDump($subKeys));
}
}
}
/**
* erasing cached translations files
*/
$this->output->writeln(PHP_EOL . '<info>Clearing SF cache ...</info>');
$finder = new Finder();
$finder->files()->in($this->rootDir . "/cache")->name('*');
foreach($finder as $file){
$fileFull = $file->getRealpath();
//$relativePath = $file->getRelativePath();
$fileName = $file->getRelativePathname();
if(preg_match('!/translations/.+$!i', $fileName)){
$this->output->writeln('removing ' . $fileName);
unlink($file);
}
}
$this->output->writeln('');
}
protected function center($text, $width = 120)
{
$len = strlen($text);
if($len<$width){
$w = (intval($width - $len)/2);
$left = str_repeat('·', $w);
$right = str_repeat('·', $width - $len - $w);
return $left . $text . $right;
}else{
return $text;
}
}
}
|