HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
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);
        }
    }
}