shimabox/pemojine

View on GitHub
scraping/src/Writer/Writer.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace SMB\Pemojine\Scraping\Writer;

use SMB\Pemojine\Config\Vendor;
use SMB\Pemojine\Scraping\Emoji\BigGroups;
use SMB\Pemojine\Scraping\Emoji\Group;

use Philo\Blade\Blade;

/**
 * 
 */
class Writer
{
    /**
     *
     * @var string
     */
    const PHPDOC_VAR = '@var';

    /**
     * 
     * @var string
     */
    const PHPDOC_PARAM = '@param';

    /**
     * 
     * @var string
     */
    const PHPDOC_RETURN = '@return';

    /**
     *
     * @var BigGroups
     */
    private $groups;

    /**
     *
     * @var string
     */
    private $outputDir;

    /**
     *
     * @var Blade
     */
    private $template;

    /**
     * 
     * @param BigGroups $groups
     */
    public function __construct(BigGroups $groups)
    {
        $this->groups = $groups;

        $this->outputDir   = realpath(dirname(__FILE__) . '/../../output');

        $template = realpath(dirname(__FILE__) . '/../../template');
        $cacheDir = realpath(dirname(__FILE__) . '/../../cache');
        $this->template = new Blade($template, $cacheDir);
    }

    /**
     * Initialize. Delete files and so on.
     * 
     * @return void
     */
    public function init()
    {
        foreach(glob($this->outputDir . '/Structure/Vendor/*') as $target){
            exec("rm -rf {$target}");
        }

        foreach(glob($this->outputDir . '/Config/*') as $target){
            exec("rm -rf {$target}");
        }
    }

    /**
     * Write files.
     * 
     * @return void
     */
    public function write()
    {
        $this->writeConfigEmojiTable($this->groups, $this->template);
        $this->writeConfigEmojiCount($this->groups, $this->template);

        list($groupAssets, $emojiTableAssets) = $this->createAssets($this->groups);
        $structureOutputDir = $this->outputDir . '/Structure/Vendor';

        $this->writeStructureBase($groupAssets, $this->template, $structureOutputDir);
        $this->writeStructure($groupAssets, $this->template, $structureOutputDir);
        $this->writeStructureEmojiTable($emojiTableAssets, $this->template, $structureOutputDir);
    }

    /**
     * Write Config/EmojiTable.php
     * 
     * @param BigGroups $groups
     * @param Blade $template
     * 
     * @return void
     */
    private function writeConfigEmojiTable(BigGroups $groups, Blade $template)
    {
        $table = [];
        $shortNameAliases = [];
        $unicodeToShortNames = [];
        foreach ($groups->getBigGroups() as $bigGroup) {
            foreach ($bigGroup->getMediumGroups() as $mediumgroup) {
                foreach ($mediumgroup->getGroups() as $group) {

                    if (!$group->isEvenOneSupported()) {
                        continue;
                    }

                    $codes = [];
                    foreach ($group->getCodes() as $code) {
                        $codes[] = $code;
                    }

                    $table[$group->shortName]['unicode'] = implode(' ', $codes);
                    $table[$group->shortName]['supportVendor'] = $this->supportVendor($group);

                    $shortNames = [];
                    foreach($group->shortNameAliases as $alias) {
                        $escapedName = $this->escapeLastBackslash($alias);
                        $shortNameAliases[$escapedName] = $group->shortName;
                        $shortNames[] = $escapedName;
                    }

                    $unicodeToShortNames[implode(' ', $codes)] = array_merge([$group->shortName], $shortNames);
                }
            }
        }

        $view = $template->view()->make('configEmojiTable', [
            'table'                 => $table,
            'shortNameAliases'      => $shortNameAliases,
            'unicodeToShortNames'   => $unicodeToShortNames,
            'escapeSingleQuotation' => function ($v) {
                return $this->escapeSingleQuotation($v);
            },
            'restoreLastBackslash'  => function ($v) {
                return $this->restoreLastBackslash($v);
            },
            'phpdocVar'             => self::PHPDOC_VAR
        ]);

        file_put_contents(
            $this->outputDir . '/Config/EmojiTable' . '.php',
            "<?php\r\r" . $view
        );
    }

    /**
     * Write Config/EmojiCount.php
     * 
     * @param BigGroups $groups
     * @param Blade $template
     * 
     * @return void
     */
    private function writeConfigEmojiCount(BigGroups $groups, Blade $template)
    {
        $bigGroupCnt = count($groups);
        $mediumGroupCnt = 0;
        $groupCnt = 0;

        foreach ($groups->getBigGroups() as $bigGroup) {
            $mediumGroupCnt += count($bigGroup);

            foreach ($bigGroup->getMediumGroups() as $mediumgroup) {
                $groupCnt += count($mediumgroup);
            }
        }

        $view = $template->view()->make('configEmojiCount', [
            'bigGroupCnt'    => $bigGroupCnt,
            'mediumGroupCnt' => $mediumGroupCnt,
            'groupCnt'       => $groupCnt,
            'phpdocVar'      => self::PHPDOC_VAR
        ]);

        file_put_contents(
            $this->outputDir . '/Config/EmojiCount' . '.php',
            "<?php\r\r" . $view
        );
    }

    /**
     * Escape backmost backward slash.
     * 
     * @param string $in
     * 
     * @return string e.g)something\ => something\\
     */
    private function escapeLastBackslash($in)
    {
        return preg_replace('/\\\\\z/', '\\\\\\', $in);
    }

    /**
     * Escape single quotation.
     * 
     * @param string $in
     * 
     * @return string e.g)some'thing => some\'thing
     */
    private function escapeSingleQuotation($in)
    {
        return preg_replace('/\'/', '\\\'', $in);
    }

    /**
     * Restore the backward slash most behind.
     * 
     * @param string $in
     * 
     * @return string
     */
    private function restoreLastBackslash($in)
    {
        return preg_replace('/\\\\\\\\\z/', '\\', $in);
    }

    /**
     * Get support vendor.
     * 
     * @param Group $group
     * 
     * @return array
     */
    private function supportVendor(Group $group)
    {
        $ret = [];
        foreach (Vendor::$VENDORS_LIST as $vendor) {
            $func = 'validWith' . $vendor;
            if ($group->$func === true) {
                $ret[] = $vendor;
            }
        }

        return $ret;
    }

    /**
     * Create assets for creating files.
     * 
     * @param BigGroups $bigGroups
     * 
     * @return array [array, array]
     */
    private function createAssets(BigGroups $bigGroups)
    {
        $groupAssets      = [];
        $emojiTableAssets = [];

        foreach ($bigGroups->getBigGroups() as $bigGroup) {

            foreach ($bigGroup->getMediumGroups() as $mediumgroup) {

                foreach ($mediumgroup->getGroups() as $group) {

                    if (!$group->isEvenOneSupported()) {
                        continue;
                    }

                    $codes = [];
                    foreach ($group->getCodes() as $index => $code) {
                        $codes[] = $code;
                    }
                    $unicode = implode(' ', $codes);

                    foreach (Vendor::$VENDORS_LIST as $vendorName) {
                        $this->poolAssets(
                            $vendorName,
                            $group,
                            $bigGroup->bigGroupName,
                            $mediumgroup->groupName,
                            $unicode,
                            $groupAssets,     // Pass by Reference
                            $emojiTableAssets // Pass by Reference
                        );
                    }

                    $this->poolAssets(
                        Vendor::ALL_SUPPORTS_VENDOR_NAME,
                        $group,
                        $bigGroup->bigGroupName,
                        $mediumgroup->groupName,
                        $unicode,
                        $groupAssets,      // Pass by Reference
                        $emojiTableAssets, // Pass by Reference
                        true
                    );
                }
            }
        }

        return [$groupAssets, $emojiTableAssets];
    }

    /**
     * Store assets for each group.
     * 
     * @param string $vendorName
     * @param Group $group
     * @param string $bigGroupName
     * @param string $mediumGroupName
     * @param string $unicode
     * @param array $groupAssets Reference
     * @param array $emojiTableAssets Reference
     * @param boolean $isCommon True if all vendors support it.
     * 
     * @return void
     */
    private function poolAssets(
        $vendorName,
        Group $group,
        $bigGroupName,
        $mediumGroupName,
        $unicode,
        &$groupAssets,
        &$emojiTableAssets,
        $isCommon = false
    )
    {
        if ($isCommon === true) {
            if ($group->isAllSupported() === false) {
                return;
            }
        } else {
            $func = 'validWith'. $vendorName;
            if ($group->$func === false) {
                return;
            }
        }

        $shortNameAliases = [];
        foreach($group->shortNameAliases as $alias) {
            $shortNameAliases[$this->escapeLastBackslash($alias)] = $group->shortName;
        }

        if (!isset($groupAssets[$vendorName]['bigGroup'])) {
            $groupAssets[$vendorName]['bigGroup'] = [];
        }
        if (!in_array($bigGroupName, $groupAssets[$vendorName]['bigGroup'])) {
            $groupAssets[$vendorName]['bigGroup'][] = $bigGroupName;
        }
        $groupAssets[$vendorName][$bigGroupName][$mediumGroupName]['groupNames'][] = $group->shortName;
        $groupAssets[$vendorName][$bigGroupName][$mediumGroupName]['groupShortNameAliases'][$group->shortName] = array_keys($shortNameAliases);

        $emojiTableAssets[$vendorName]['table'][$group->shortName] = $unicode;
        foreach ($shortNameAliases as $alias => $baseName) {
            $emojiTableAssets[$vendorName]['shortNameAliases'][$alias] = $baseName;
        }
    }

    /**
     * Write Structure/Vendor/{$VendorName}.php
     * 
     * @param array $assets
     * @param Blade $template
     * @param string $outputDir
     * 
     * @return void
     */
    private function writeStructureBase(
        array $assets,
        Blade $template,
        $outputDir
    )
    {
        foreach ($assets as $vendorName => $groups) {

            $classes = [];

            foreach ($groups['bigGroup'] as $bigGroupName) {
                $classes[] = $vendorName . '\\' . $this->normalizeBigGroupName($bigGroupName) . '::class';
            }

            $viewParam = [];
            $viewParam['vendorName']   = $vendorName;
            $viewParam['classes']      = $classes;
            $viewParam['phpdocReturn'] = self::PHPDOC_RETURN;

            $view = $template->view()->make('structureBase', $viewParam);
            file_put_contents(
                $outputDir . '/' . $vendorName . '.php',
                "<?php\r\r" . $view
            );
        }
    }

    /**
     * Write Structure/Vendor/{$VendorName}/{$BigGroupName}.php
     * 
     * @param array $assets
     * @param Blade $template
     * @param string $outputDir
     * 
     * @return void
     */
    private function writeStructure(
        array $assets,
        Blade $template,
        $outputDir
    )
    {
        foreach ($assets as $vendorName => $groups) {

            foreach ($groups['bigGroup'] as $bigGroupName) {

                $viewParam = [];

                foreach ($groups[$bigGroupName] as $mediumGroupName => $group) {

                    $viewParam['mediumGroups'][$mediumGroupName] = [
                        'parent'   => $bigGroupName,
                        'children' => $group['groupNames']
                    ];

                    foreach ($group['groupNames'] as $groupName) {
                        $viewParam['groups'][$groupName] = [
                            'parent'  => $mediumGroupName,
                            'aliases' => $group['groupShortNameAliases'][$groupName]
                        ];
                    }

                }

                $viewParam['vendorName']              = $vendorName;
                $viewParam['className']               = $this->normalizeBigGroupName($bigGroupName);
                $viewParam['bigGroup'][$bigGroupName] = array_keys($groups[$bigGroupName]);
                $viewParam['escapeSingleQuotation']   = function ($v) {
                    return $this->escapeSingleQuotation($v);
                };
                $viewParam['restoreLastBackslash']    = function ($v) {
                    return $this->restoreLastBackslash($v);
                };
                $viewParam['phpdocVar']               = self::PHPDOC_VAR;
                $viewParam['phpdocReturn']            = self::PHPDOC_RETURN;

                if (! file_exists($outputDir . '/' . $vendorName)) {
                    mkdir($outputDir . '/' . $vendorName, 0777);
                }

                $view = $template->view()->make('structure', $viewParam);
                file_put_contents(
                    $outputDir . '/' . $vendorName . '/' . $this->normalizeBigGroupName($bigGroupName) . '.php',
                    "<?php\r\r" . $view
                );
            }
        }
    }

    /**
     * Write Structure/Vendor/{$VendorName}/EmojiTable.php
     * 
     * @param array $assets
     * @param Blade $template
     * @param string $outputDir
     * 
     * @return void
     */
    private function writeStructureEmojiTable(
        array $assets,
        Blade $template,
        $outputDir
    )
    {
        foreach ($assets as $vendorName => $contents) {
            $viewParam = [];
            $viewParam['vendorName']            = $vendorName;
            $viewParam['table']                 = $contents['table'];
            $viewParam['shortNameAliases']      = $contents['shortNameAliases'];
            $viewParam['escapeSingleQuotation'] = function ($v) {
                return $this->escapeSingleQuotation($v);
            };
            $viewParam['restoreLastBackslash']  = function ($v) {
                return $this->restoreLastBackslash($v);
            };
            $viewParam['phpdocVar']             = self::PHPDOC_VAR;

            if (! file_exists($outputDir . '/' . $vendorName)) {
                mkdir($outputDir . '/' . $vendorName, 0777);
            }

            $view = $template->view()->make('emojiTable', $viewParam);
            file_put_contents(
                $outputDir . '/' . $vendorName . '/EmojiTable.php',
                "<?php\r\r" . $view
            );
        }
    }

    /**
     * Normalize the big group name. Because it is used as a class name.
     * 
     * @param string $bigGroupName
     * 
     * @return string
     */
    private function normalizeBigGroupName($bigGroupName)
    {
        return str_replace(array(' ', ' ', '&'), '', $bigGroupName);
    }
}