File: D:/HostingSpaces/SBogers95/rentman.io/app/Komma/Shop/TranslationInstallationController.php
<?php
namespace App\Komma\Shop;
use Illuminate\Console\Command;
/**
* Class InstallationController
*/
class TranslationInstallationController
{
/**
* @var string A folder where locale folders (ex: en, nl as iso2) are located wherein translations files can be found
*/
private $translationsFolder;
/**
* @var string The folder to the lang resource folder. Usually this is resources/lang
*/
private $laravelsTranslationsFolder;
public function __construct()
{
$this->translationsFolder = __DIR__.DIRECTORY_SEPARATOR.'Translations'.DIRECTORY_SEPARATOR;
$this->laravelsTranslationsFolder = resource_path('lang');
$this->laravelsTranslationsFolder = $this->laravelsTranslationsFolder.DIRECTORY_SEPARATOR;
}
/**
* Installs the shop translations to resources\lang folders depending on the folders in the shops Translations folder
* @param Command $command
* @param bool $installViaCopy
*/
public function translations(Command $command, $installViaCopy = false)
{
$folders = $this->getShopTranslationFolders();
$command->info('Detected the following shop translation folders: '.implode(', ', $folders));
//Create the folder in Laravel's lang resource folder if it does not exists
$this->createLanguageFoldersForLaravel($folders, $command);
//Get the files from the iso2 folders and create files that include them in Laravel's language resource directory (Pretty much like symbolic linking)
$installation = $this->getInstallation($folders, $command);
$command->info('Installing the shop translation files...');
//Install the translations
foreach ($installation as $relativeFile) {
$dirnameToCheck = dirname($this->laravelsTranslationsFolder.$relativeFile);
if (file_exists($dirnameToCheck) === false) {
mkdir($dirnameToCheck, 0777, true);
}
if ($installViaCopy) {
//Install by copy
if (! copy($this->translationsFolder.$relativeFile,
$this->laravelsTranslationsFolder.$relativeFile)) {
throw new \RuntimeException("Could not install language file '".$relativeFile."' to '".$this->laravelsTranslationsFolder.$relativeFile."'. Check directory permissions first");
}
} else {
//Install by requiring
file_put_contents($this->laravelsTranslationsFolder.$relativeFile, [
'<?php'.PHP_EOL,
'return require("'.$this->translationsFolder.$relativeFile.'");'.PHP_EOL.PHP_EOL,
]);
}
}
$command->info('Installed the shop translation files!');
}
/**
* Builds and returns an array that represents the installation that needs to be done or undone.
* For example if you give it the folder Translations (next to this file) it will return for example an array like this:
* ["en/shop/shop.sidebar.php", "nl/shop/shop.sidebar.php"]
*
* @param array $shopTranslationFolders An array containing folder names from the shop Translations folder.
* @param Command $command The artisan command. Used for logging
* @return array
*/
public function getInstallation(array $shopTranslationFolders, Command $command): array
{
$translationFilesCount = 0;
$isoFolderCount = 0;
$destinationsAndSourceFiles = []; //The keys are the destination folders. Values are numeric arrays that contain absolute paths to files that will be put in the destination folders
foreach ($shopTranslationFolders as $iso2Folder) {
// $destinationsAndSourceFiles[$this->laravelsTranslationsFolder.DIRECTORY_SEPARATOR.$iso2Folder] = [];
$translationFoldersAndFiles = $this->scanDirRecursivelyAndReturnPhpFiles(__DIR__.DIRECTORY_SEPARATOR.'Translations'.DIRECTORY_SEPARATOR.$iso2Folder);
foreach ($translationFoldersAndFiles as $translationFoldersAndFile) {
//Skip if folder is the current folder (.) or the parent folder (..)
if ($translationFoldersAndFile == '.' || $translationFoldersAndFile == '..') {
continue;
}
if (! is_dir($this->translationsFolder.DIRECTORY_SEPARATOR.$translationFoldersAndFile)) {
// $destinationsAndSourceFiles[$this->laravelsTranslationsFolder.DIRECTORY_SEPARATOR.$iso2Folder][] = $translationFoldersAndFile;
$destinationsAndSourceFiles[] = $iso2Folder.DIRECTORY_SEPARATOR.$translationFoldersAndFile;
$translationFilesCount++;
}
}
$isoFolderCount++;
}
if ($command) {
$command->info('Detected '.$translationFilesCount.' shop translation file(s) in '.$isoFolderCount.' shop translation language (iso2) folder(s)');
}
return $destinationsAndSourceFiles;
}
/**
* Returns all file paths that are below a certain directory. Relative to the root directory
*
* @param $root string The directory in which we start to search recursively for files
* @param $startRoot string The root directory that the search was started in. Internally used. Must not be used by humans
* @param array $files internal carrier variable. Humans must not use this variable
* @return array
*/
private function scanDirRecursivelyAndReturnPhpFiles($root, $startRoot = null, &$files = []):array
{
if ($startRoot == null) {
$startRoot = $root;
}
if (is_file($root) || ! is_dir($root)) {
if (is_file($root) && pathinfo($root, PATHINFO_EXTENSION) == 'php') {
$files[] = str_replace($startRoot.DIRECTORY_SEPARATOR, '', $root);
}
return $files;
}
// starts the scan
$dirsAndFiles = scandir($root);
foreach ($dirsAndFiles as $dirOrFile) {
if ($dirOrFile == '.' || $dirOrFile == '..') {
continue; // skip . and ..
}
$path = $root.'/'.$dirOrFile;
$this->scanDirRecursivelyAndReturnPhpFiles($path, $startRoot, $files);
}
return $files;
}
/**
* Returns an array of strings containing the names of the folders in the shop's translations folder
*
* @return string[]
*/
private function getShopTranslationFolders(): array
{
$translationFoldersAndFiles = scandir(__DIR__.DIRECTORY_SEPARATOR.'Translations'.DIRECTORY_SEPARATOR, SCANDIR_SORT_ASCENDING);
$folders = [];
foreach ($translationFoldersAndFiles as $translationFoldersAndFile) {
//Skip if folder is the current folder (.) or the parent folder (..)
if ($translationFoldersAndFile == '.' || $translationFoldersAndFile == '..') {
continue;
}
//Add
if (is_dir($this->translationsFolder.DIRECTORY_SEPARATOR.$translationFoldersAndFile)) {
$folders[] = $translationFoldersAndFile;
}
}
return $folders;
}
/**
* Receives an array containing names of folders that should exist in laravels lang resource folder.
*
* @param array $languageFolderNames
* @param Command $command The artisan command. Used to log progress
*/
private function createLanguageFoldersForLaravel(array $languageFolderNames, Command $command = null): void
{
foreach ($languageFolderNames as $iso2Folder) {
$currentIso2ResourceFolder = $this->laravelsTranslationsFolder.DIRECTORY_SEPARATOR.$iso2Folder;
if (! file_exists($currentIso2ResourceFolder)) {
if (! mkdir($currentIso2ResourceFolder, 0777, true)) {
throw new \RuntimeException("The iso2 language resource folder '".$currentIso2ResourceFolder."' could not be created and therefore the '".$iso2Folder."' shop translation could not be installed");
} else {
if ($command) {
$command->info("Shop language folder '".$currentIso2ResourceFolder."' created in laravels lang resource folder because it did not exist: '".$this->laravelsTranslationsFolder."'");
}
}
}
}
}
/**
* Uninstalls shop translations
* @param Command $command
*/
public function translationsUninstall(Command $command)
{
$folders = $this->getShopTranslationFolders();
$command->info('Detected the following shop translation folders: '.implode(', ', $folders));
//Create the folder in Laravel's lang resource folder if it does not exists
$this->createLanguageFoldersForLaravel($folders, $command);
//Get the files from the iso2 folders and delete files that include them in Laravel's language resource directory (Pretty much like symbolic linking)
$installation = $this->getInstallation($folders, $command);
$command->info('Deleting the shop translation files...');
//delete the translations
foreach ($installation as $relativeFile) {
if (file_exists($this->laravelsTranslationsFolder.$relativeFile) && ! unlink($this->laravelsTranslationsFolder.$relativeFile)) {
throw new \RuntimeException('Installation (partially) aborted. Could not uninstall translation file: '.$this->laravelsTranslationsFolder.$relativeFile);
}
}
foreach ($installation as $relativeFile) {
$dir = dirname($this->laravelsTranslationsFolder.$relativeFile);
$this->forceRmDir($dir);
if (file_exists($dir)) {
throw new \RuntimeException('Installation (partially) aborted. Could not delete directory: '.$dir.'. Try to delete it yourself and uninstall again.');
}
}
$command->info('Deleted the shop translation files!');
}
/**
* Removes the specifies directory after deleting all items in it
*
* @param $dir
*/
public function forceRmDir($dir)
{
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != '.' && $object != '..') {
if (filetype($dir.'/'.$object) == 'dir') {
$this->forceRmDir($dir.'/'.$object);
} else {
unlink($dir.'/'.$object);
}
}
}
reset($objects);
rmdir($dir);
}
}
}