/**
  * Setup the test environment.
  *
  * - Remove all previous lang files before each test
  * - Set custom configuration paths
  */
 public function setUp()
 {
     parent::setUp();
     Tools::unlinkGlobFiles(self::LANG_DIR_PATH . '/*/message*.php');
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'lang_folder_path', self::LANG_DIR_PATH);
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'folders', self::MOCK_DIR_PATH_GLOBAL);
     /** @noinspection PhpVoidFunctionResultUsedInspection */
     Artisan::call('localization:missing', array('--no-interaction' => true, '--output-flat' => true, '--new-value' => '%LEMMA POTSKY'));
 }
 public function testArraySetDotFirstLevel()
 {
     $array = array();
     Tools::arraySetDotFirstLevel($array, 'a.b.c', true);
     $this->assertTrue($array['a']['b.c']);
     Tools::arraySetDotFirstLevel($array, 'a.b.c', true);
     $this->assertNull(@$array['a']['b']['c']);
     Tools::arraySetDotFirstLevel($array, null, true);
     /** @var bool $array */
     $this->assertTrue($array);
 }
 /**
  * Setup the test environment.
  *
  * - Remove all previous lang files before each test
  * - Set custom configuration paths
  */
 public function setUp()
 {
     parent::setUp();
     Tools::unlinkGlobFiles(self::LANG_DIR_PATH . '/*/message*.php');
     self::$langFile = self::LANG_DIR_PATH . '/en/message.php';
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'lang_folder_path', self::LANG_DIR_PATH);
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'folders', self::MOCK_DIR_PATH_GLOBAL);
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'code_style.fixers', array('align_double_arrow', 'short_array_syntax'));
     // Remove all saved access token for translation API
     $translator = new \MicrosoftTranslator\Client(array('api_client_id' => true, 'api_client_secret' => true));
     $translator->getAuth()->getGuard()->deleteAllAccessTokens();
 }
 /**
  * Setup the test environment.
  *
  * - Remove all previous lang files before each test
  * - Create 10 backup files, one per day
  */
 public function setUp()
 {
     parent::setUp();
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'lang_folder_path', self::LANG_DIR_PATH);
     Config::set(Localization::PREFIX_LARAVEL_CONFIG . 'folders', self::MOCK_DIR_PATH_GLOBAL);
     \Potsky\LaravelLocalizationHelpers\Factory\Tools::unlinkGlobFiles(self::LANG_DIR_PATH . '/*/message*.php');
     $manager = new Localization(new MessageBag());
     for ($i = 0; $i < 10; $i++) {
         $time = $manager->getBackupDate($i);
         touch(self::LANG_DIR_PATH . '/en/message' . $time . '.php');
         touch(self::LANG_DIR_PATH . '/fr/message' . $time . '.php');
     }
 }
 /**
  * Setup the test environment.
  *
  * - Remove all previous lang files before each test
  * - Set custom configuration paths
  */
 public function setUp()
 {
     parent::setUp();
     Tools::unlinkGlobFiles(self::LANG_DIR_PATH . '/*/message*.php');
     self::$langFile = self::LANG_DIR_PATH . '/en/message.php';
 }
 /**
  * Delete backup files
  *
  * @param string     $lang_folder_path
  * @param int        $days
  * @param bool|false $dryRun
  * @param string     $ext
  *
  * @return bool
  */
 public function deleteBackupFiles($lang_folder_path, $days = 0, $dryRun = false, $ext = 'php')
 {
     if ($days < 0) {
         return false;
     }
     try {
         $dir_lang = $this->getLangPath($lang_folder_path);
     } catch (Exception $e) {
         switch ($e->getCode()) {
             //@codeCoverageIgnoreStart
             case self::NO_LANG_FOLDER_FOUND_IN_THESE_PATHS:
                 $this->messageBag->writeError("No lang folder found in these paths:");
                 foreach ($e->getParameter() as $path) {
                     $this->messageBag->writeError("- " . $path);
                 }
                 break;
                 //@codeCoverageIgnoreEnd
             //@codeCoverageIgnoreEnd
             case self::NO_LANG_FOLDER_FOUND_IN_YOUR_CUSTOM_PATH:
                 $this->messageBag->writeError('No lang folder found in your custom path: "' . $e->getParameter() . '"');
                 break;
         }
         return false;
     }
     $return = true;
     foreach ($this->getBackupFiles($dir_lang) as $file) {
         $fileDate = $this->getBackupFileDate($file, $ext);
         // @codeCoverageIgnoreStart
         // Cannot happen because of glob but safer
         if (is_null($fileDate)) {
             $this->messageBag->writeError('Unable to detect date in file ' . $file);
             $return = false;
             continue;
         }
         // @codeCoverageIgnoreEnd
         if ($this->isDateOlderThanDays($fileDate, $days)) {
             if ($dryRun === true) {
                 $deleted = true;
             } else {
                 $deleted = unlink($file);
             }
             if ($deleted === true) {
                 $this->messageBag->writeInfo('Deleting file ' . $file);
             } else {
                 $this->messageBag->writeError('Unable to delete file ' . $file);
                 $return = false;
             }
         } else {
             $this->messageBag->writeInfo('Skip file ' . $file . ' (not older than ' . $days . 'day' . Tools::getPlural($days) . ')');
         }
     }
     return $return;
 }
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function fire()
 {
     $folders = $this->manager->getPath($this->folders);
     $this->display = !$this->option('silent');
     $extension = $this->option('php-file-extension');
     $obsolete_prefix = empty($this->obsolete_array_key) ? '' : $this->obsolete_array_key . '.';
     //////////////////////////////////////////////////
     // Display where translations are searched in //
     //////////////////////////////////////////////////
     if ($this->option('verbose')) {
         $this->writeLine("Lemmas will be searched in the following directories:");
         foreach ($folders as $path) {
             $this->writeLine('    <info>' . $path . '</info>');
         }
         $this->writeLine('');
     }
     ////////////////////////////////
     // Parse all lemmas from code //
     ////////////////////////////////
     $lemmas = $this->manager->extractTranslationsFromFolders($folders, $this->trans_methods, $extension);
     if (count($lemmas) === 0) {
         $this->writeComment("No lemma has been found in code.");
         $this->writeLine("I have searched recursively in PHP files in these directories:");
         foreach ($this->manager->getPath($this->folders) as $path) {
             $this->writeLine("    " . $path);
         }
         $this->writeLine("for these functions/methods:");
         foreach ($this->trans_methods as $k => $v) {
             $this->writeLine("    " . $k);
         }
         return self::SUCCESS;
     }
     $this->writeLine(count($lemmas) > 1 ? count($lemmas) . " lemmas have been found in code" : "1 lemma has been found in code");
     if ($this->option('verbose')) {
         foreach ($lemmas as $key => $value) {
             if (strpos($key, '.') !== false) {
                 $this->writeLine('    <info>' . $key . '</info> in file <comment>' . $this->manager->getShortPath($value) . '</comment>');
             }
         }
     }
     /////////////////////////////////////////////
     // Convert dot lemmas to structured lemmas //
     /////////////////////////////////////////////
     if ($this->option('output-flat')) {
         $lemmas_structured = $this->manager->convertLemmaToFlatArray($lemmas);
     } else {
         $lemmas_structured = $this->manager->convertLemmaToStructuredArray($lemmas);
     }
     $this->writeLine('');
     /////////////////////////////////////
     // Generate lang files :           //
     // - add missing lemmas on top     //
     // - keep already defined lemmas   //
     // - add obsolete lemmas on bottom //
     /////////////////////////////////////
     try {
         $dir_lang = $this->manager->getLangPath($this->lang_folder_path);
     } catch (Exception $e) {
         switch ($e->getCode()) {
             //@codeCoverageIgnoreStart
             case Localization::NO_LANG_FOLDER_FOUND_IN_THESE_PATHS:
                 $this->writeError("No lang folder found in these paths:");
                 foreach ($e->getParameter() as $path) {
                     $this->writeError("- " . $path);
                 }
                 break;
                 //@codeCoverageIgnoreEnd
             //@codeCoverageIgnoreEnd
             case Localization::NO_LANG_FOLDER_FOUND_IN_YOUR_CUSTOM_PATH:
                 $this->writeError('No lang folder found in your custom path: "' . $e->getParameter() . '"');
                 break;
         }
         $this->writeLine('');
         return self::ERROR;
     }
     $job = array();
     $there_are_new = false;
     $this->writeLine('Scan files:');
     foreach (scandir($dir_lang) as $lang) {
         if (Tools::isValidDirectory($dir_lang, $lang)) {
             foreach ($lemmas_structured as $family => $array) {
                 if (in_array($family, $this->ignore_lang_files)) {
                     if ($this->option('verbose')) {
                         $this->writeLine('');
                         $this->writeInfo("    ! Skip lang file '{$family}' !");
                     }
                     continue;
                 }
                 $file_lang_path = $dir_lang . DIRECTORY_SEPARATOR . $lang . DIRECTORY_SEPARATOR . $family . '.php';
                 if ($this->option('verbose')) {
                     $this->writeLine('');
                 }
                 $this->writeLine('    ' . $this->manager->getShortPath($file_lang_path));
                 if (!is_writable(dirname($file_lang_path))) {
                     // @codeCoverageIgnoreStart
                     $this->writeError("    > Unable to write file in directory " . dirname($file_lang_path));
                     return self::ERROR;
                     // @codeCoverageIgnoreEnd
                 }
                 if (!file_exists($file_lang_path)) {
                     // @codeCoverageIgnoreStart
                     $this->writeInfo("    > File has been created");
                     // @codeCoverageIgnoreEnd
                 }
                 if (!touch($file_lang_path)) {
                     // @codeCoverageIgnoreStart
                     $this->writeError("    > Unable to touch file {$file_lang_path}");
                     return self::ERROR;
                     // @codeCoverageIgnoreEnd
                 }
                 if (!is_readable($file_lang_path)) {
                     // @codeCoverageIgnoreStart
                     $this->writeError("    > Unable to read file {$file_lang_path}");
                     return self::ERROR;
                     // @codeCoverageIgnoreEnd
                 }
                 if (!is_writable($file_lang_path)) {
                     // @codeCoverageIgnoreStart
                     $this->writeError("    > Unable to write in file {$file_lang_path}");
                     return self::ERROR;
                     // @codeCoverageIgnoreEnd
                 }
                 /** @noinspection PhpIncludeInspection */
                 $a = (include $file_lang_path);
                 $old_lemmas_with_obsolete = is_array($a) ? array_dot($a) : array();
                 $new_lemmas = array_dot($array);
                 $final_lemmas = array();
                 $display_already_comment = false;
                 $something_to_do = false;
                 $i = 0;
                 // Remove the obsolete prefix key
                 $old_lemmas = array();
                 $obsolete_prefix_length = strlen($obsolete_prefix);
                 foreach ($old_lemmas_with_obsolete as $key => $value) {
                     if (starts_with($key, $obsolete_prefix)) {
                         $key = substr($key, $obsolete_prefix_length);
                         if (!isset($old_lemmas[$key])) {
                             $old_lemmas[$key] = $value;
                         }
                     } else {
                         $old_lemmas[$key] = $value;
                     }
                 }
                 $obsolete_lemmas = array_diff_key($old_lemmas, $new_lemmas);
                 $welcome_lemmas = array_diff_key($new_lemmas, $old_lemmas);
                 $already_lemmas = array_intersect_key($old_lemmas, $new_lemmas);
                 // disable check for obsolete lemma and consolidate with already_lemmas
                 if ($this->option('disable-obsolete-check')) {
                     $already_lemmas = array_unique($obsolete_lemmas + $already_lemmas);
                     $obsolete_lemmas = array();
                 }
                 ksort($obsolete_lemmas);
                 ksort($welcome_lemmas);
                 ksort($already_lemmas);
                 //////////////////////////
                 // Deal with new lemmas //
                 //////////////////////////
                 if (count($welcome_lemmas) > 0) {
                     $display_already_comment = true;
                     $something_to_do = true;
                     $there_are_new = true;
                     $final_lemmas["POTSKY___NEW___POTSKY"] = "POTSKY___NEW___POTSKY";
                     $this->writeInfo('        ' . ($c = count($welcome_lemmas)) . ' new string' . Tools::getPlural($c) . ' to translate');
                     foreach ($welcome_lemmas as $key => $value) {
                         if ($this->option('verbose')) {
                             $this->writeLine("            <info>" . $key . "</info> in " . $this->manager->getShortPath($value));
                         }
                         if (!$this->option('no-comment')) {
                             $final_lemmas['POTSKY___COMMENT___POTSKY' . $i] = "Defined in file {$value}";
                             $i = $i + 1;
                         }
                         $key_last_token = explode('.', $key);
                         if ($this->option('translation')) {
                             $translation = $this->manager->translate(end($key_last_token), $lang);
                         } else {
                             $translation = end($key_last_token);
                         }
                         if (strtolower($this->option('new-value')) === 'null') {
                             $translation = null;
                         } else {
                             $translation = str_replace('%LEMMA', $translation, $this->option('new-value'));
                         }
                         array_set($final_lemmas, $key, $translation);
                     }
                 }
                 ///////////////////////////////
                 // Deal with existing lemmas //
                 ///////////////////////////////
                 if (count($already_lemmas) > 0) {
                     if ($this->option('verbose')) {
                         $this->writeLine('        ' . ($c = count($already_lemmas)) . ' already translated string' . Tools::getPlural($c));
                     }
                     $final_lemmas["POTSKY___OLD___POTSKY"] = "POTSKY___OLD___POTSKY";
                     foreach ($already_lemmas as $key => $value) {
                         array_set($final_lemmas, $key, $value);
                     }
                 }
                 ///////////////////////////////
                 // Deal with obsolete lemmas //
                 ///////////////////////////////
                 if (count($obsolete_lemmas) > 0) {
                     $protected_already_included = false;
                     // Remove all dynamic fields
                     foreach ($obsolete_lemmas as $key => $value) {
                         foreach ($this->never_obsolete_keys as $remove) {
                             if (strpos($key, '.' . $remove . '.') !== false || starts_with($key, $remove . '.')) {
                                 if ($this->option('verbose')) {
                                     $this->writeLine("        <comment>" . $key . "</comment> is protected as a dynamic lemma");
                                 }
                                 unset($obsolete_lemmas[$key]);
                                 if ($protected_already_included === false) {
                                     $final_lemmas["POTSKY___PROTECTED___POTSKY"] = "POTSKY___PROTECTED___POTSKY";
                                     $protected_already_included = true;
                                 }
                                 // Given that this lemma is never obsolete, we need to send it back to the final lemma array
                                 array_set($final_lemmas, $key, $value);
                             }
                         }
                     }
                 }
                 /////////////////////////////////////
                 // Fill the final lemmas array now //
                 /////////////////////////////////////
                 if (count($obsolete_lemmas) > 0) {
                     $display_already_comment = true;
                     $something_to_do = true;
                     if ($this->option('no-obsolete')) {
                         $this->writeComment("        " . ($c = count($obsolete_lemmas)) . ' obsolete string' . Tools::getPlural($c) . ' (will be deleted)');
                     } else {
                         $this->writeComment("        " . ($c = count($obsolete_lemmas)) . ' obsolete string' . Tools::getPlural($c) . ' (can be deleted manually in the generated file)');
                         $final_lemmas["POTSKY___OBSOLETE___POTSKY"] = "POTSKY___OBSOLETE___POTSKY";
                         foreach ($obsolete_lemmas as $key => $value) {
                             if ($this->option('verbose')) {
                                 $this->writeLine("            <comment>" . $key . "</comment>");
                             }
                             array_set($final_lemmas, $obsolete_prefix . $key, $value);
                         }
                     }
                 }
                 // Flat style
                 if ($this->option('output-flat')) {
                     $final_lemmas = array_dot($final_lemmas);
                 }
                 if ($something_to_do === true || $this->option('force')) {
                     $content = var_export($final_lemmas, true);
                     $content = preg_replace("@'POTSKY___COMMENT___POTSKY[0-9]*' => '(.*)',@", '// $1', $content);
                     $content = str_replace(array("'POTSKY___NEW___POTSKY' => 'POTSKY___NEW___POTSKY',", "'POTSKY___OLD___POTSKY' => 'POTSKY___OLD___POTSKY',", "'POTSKY___PROTECTED___POTSKY' => 'POTSKY___PROTECTED___POTSKY',", "'POTSKY___OBSOLETE___POTSKY' => 'POTSKY___OBSOLETE___POTSKY',"), array('//============================== New strings to translate ==============================//', $display_already_comment === true ? '//==================================== Translations ====================================//' : '', '//============================== Dynamic protected strings =============================//', '//================================== Obsolete strings ==================================//'), $content);
                     $file_content = "<?php\n";
                     if (!$this->option('no-date')) {
                         $a = " Generated via \"php artisan " . $this->argument('command') . "\" at " . date("Y/m/d H:i:s") . " ";
                         $file_content .= "/" . str_repeat('*', strlen($a)) . "\n" . $a . "\n" . str_repeat('*', strlen($a)) . "/\n";
                     }
                     $file_content .= "\nreturn " . $content . ";";
                     $job[$file_lang_path] = $file_content;
                 } else {
                     if ($this->option('verbose')) {
                         $this->writeLine("        > <comment>Nothing to do for this file</comment>");
                     }
                 }
             }
         }
     }
     ///////////////////////////////////////////
     // Silent mode                           //
     // only return an exit code on new lemma //
     ///////////////////////////////////////////
     if ($this->option('silent')) {
         if ($there_are_new === true) {
             return self::ERROR;
         } else {
             // @codeCoverageIgnoreStart
             return self::SUCCESS;
             // @codeCoverageIgnoreEnd
         }
     }
     ///////////////////////////////////////////
     // Normal mode                           //
     ///////////////////////////////////////////
     if (count($job) > 0) {
         if ($this->option('no-interaction')) {
             $do = true;
         } else {
             $this->writeLine('');
             $do = $this->ask('Do you wish to apply these changes now? [yes|no]') === 'yes';
             $this->writeLine('');
         }
         // @codeCoverageIgnoreEnd
         if ($do === true) {
             if (!$this->option('no-backup')) {
                 $this->writeLine('Backup files:');
                 $now = $this->manager->getBackupDate();
                 foreach ($job as $file_lang_path => $file_content) {
                     $backup_path = $this->manager->getBackupPath($file_lang_path, $now, $extension);
                     if (!$this->option('dry-run')) {
                         rename($file_lang_path, $backup_path);
                     }
                     $this->writeLine("    <info>" . $this->manager->getShortPath($file_lang_path) . "</info> -> <info>" . $this->manager->getShortPath($backup_path) . "</info>");
                 }
                 $this->writeLine('');
             }
             $this->writeLine('Save files:');
             $open_files = '';
             foreach ($job as $file_lang_path => $file_content) {
                 if (!$this->option('dry-run')) {
                     file_put_contents($file_lang_path, $file_content);
                 }
                 $this->writeLine("    <info>" . $this->manager->getShortPath($file_lang_path) . "</info>");
                 // Fix code style
                 if (!empty($this->code_style_level) || !empty($this->code_style_fixers)) {
                     try {
                         $this->manager->fixCodeStyle($file_lang_path, $this->code_style_fixers, $this->code_style_level);
                     } catch (Exception $e) {
                         $this->writeError("    Cannot fix code style (" . $e->getMessage() . ")");
                     }
                     // @codeCoverageIgnoreEnd
                 }
                 // @codeCoverageIgnoreStart
                 if ($this->option('editor')) {
                     $open_files .= ' ' . escapeshellarg($file_lang_path);
                 }
                 // @codeCoverageIgnoreEnd
             }
             $this->writeLine('');
             $this->writeInfo('Process done!');
             // @codeCoverageIgnoreStart
             if ($this->option('editor')) {
                 exec($this->editor . $open_files);
             }
             // @codeCoverageIgnoreEnd
             // @codeCoverageIgnoreStart
         } else {
             $this->writeLine('');
             $this->writeComment('Process aborted. No file has been changed.');
         }
     } else {
         $this->writeLine('');
         $this->writeInfo('Drink a Piña colada and/or smoke Super Skunk, you have nothing to do!');
     }
     $this->writeLine('');
     return self::SUCCESS;
 }