njuhel/php-swagger-to-md

View on GitHub
src/Swagger2md.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/*
 * Copyright 2016 Nicolas JUHEL<swaggervalidator@nabbar.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Swagger2md;

/**
 * Description of Swagger2md
 *
 * @author Nicolas JUHEL<swaggervalidator@nabbar.com>
 */
class Swagger2md
{

    const version = '1.0.0';

    /**
     *
     * @var \Swagger2md\SwaggerValidator\Object\Swagger
     */
    protected $swagger;

    /**
     *
     * @var integer
     */
    protected static $verboseLevel = 0;

    /**
     *
     * @var \Twig_Environment
     */
    protected $twigTpl;

    /**
     *
     * @var string
     */
    protected $tempFolder;

    /**
     *
     * @var string
     */
    protected $templateFolder;

    /**
     *
     * @var string
     */
    protected $output;

    /**
     *
     * @var \Swagger2md\Swagger2md
     */
    private static $instance;

    /**
     *
     * @var array
     */
    protected $suffixObject;

    /**
     * Private construct for singleton
     */
    private function __construct()
    {

    }

    public function loadSwaggerFile($swaggerFile = null)
    {
        $params = getopt('h::v', array(
            'templates::',
            'tempDir::',
            'output::',
            'help',
            'version',
            'verbose',
        ));

        if (isset($params['help']) || isset($params['h'])) {
            $this->showVersion();
            $this->showUsage();
            $this->showHelp();
            $this->exitCode(0);
        }

        if (isset($params['version'])) {
            $this->showVersion();
            $this->exitCode(0);
        }

        if (isset($params['v'])) {
            if (is_array($params['v']) && count($params['v']) > 2) {
                unset($params['v']);
                $params['vvv'] = true;
            }
            elseif (is_array($params['v']) && count($params['v']) > 1) {
                unset($params['v']);
                $params['vv'] = true;
            }
        }

        if (isset($params['verbose']) || isset($params['vvv'])) {
            $this->showVersion();
            self::$verboseLevel = 3;
            self::printOutV('Verbose : maximum');
        }
        elseif (isset($params['vv'])) {
            $this->showVersion();
            self::$verboseLevel = 2;
            self::printOutV('Verbose : medium');
        }
        elseif (isset($params['v'])) {
            $this->showVersion();
            self::$verboseLevel = 1;
            self::printOutV('Verbose : minimum');
        }
        else {
            self::$verboseLevel = 0;
        }

        if (self::$verboseLevel < 3) {
            \SwaggerValidator\Common\Context::setConfigDropAllDebugLog();
        }

        if (!empty($params['tempDir'])) {
            $temp = $params['tempDir'];
        }

        if (!empty($params['output'])) {
            $output = $params['output'];
            self::printOutVV('Asked to ouput to : ' . $output);
        }

        if (!empty($params['templates'])) {
            $this->templateFolder = $this->checkTemplates($params['templates']);
        }
        else {
            $this->templateFolder = $this->checkTemplates();
        }

        if (!empty($temp)) {
            $this->twigTpl = new \Twig_Environment(new \Twig_Loader_Filesystem($this->templateFolder), array(
                'cache'            => $temp,
                'debug'            => (self::$verboseLevel > 0),
                'strict_variables' => false,
                'optimizations'    => 0,
                'autoescape'       => false,
            ));
        }
        else {
            $this->twigTpl = new \Twig_Environment(new \Twig_Loader_Filesystem($this->templateFolder), array(
                'cache'            => false,
                'debug'            => (self::$verboseLevel > 0),
                'strict_variables' => false,
                'optimizations'    => 0,
                'autoescape'       => false,
            ));
        }

        if (empty($swaggerFile) || substr($swaggerFile, 0, 1) == '-') {
            self::printError('Missing argument swaggerFile !');
            $this->showUsage();
            $this->exitCode(1);
        }

        if (!empty($output) && touch($output)) {
            $this->output = realpath($output);
            self::printOutV('The result will be saved into the file : ' . $this->output);
        }
        else {
            $this->output = 'php://stdout';
            self::printOutV('The result will be print in the stdout.');
        }

        \SwaggerValidator\Swagger::setSwaggerFile(getcwd() . DIRECTORY_SEPARATOR . $swaggerFile);
        $this->swagger = \SwaggerValidator\Swagger::load(new \Swagger2md\Context());
    }

    /**
     * get the singleton of this object
     * @return \Swagger2md\Swagger2md
     */
    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new static();
        }

        return self::$instance;
    }

    /**
     * replace the singleton of this object
     */
    public static function setInstance(\Swagger2md\Swagger2md $instance)
    {
        self::$instance = $instance;
    }

    /**
     * prune the singleton of this object
     */
    public static function pruneInstance()
    {
        self::$instance = null;
    }

    public function markdown()
    {
        file_put_contents($this->output, $this->swagger->markdown(new \Swagger2md\Context()));
    }

    public static function printError($message)
    {
        fwrite(STDERR, str_replace("\n", PHP_EOL, $message . "\n"));
    }

    public static function printOut($message)
    {
        fwrite(STDOUT, str_replace("\n", PHP_EOL, $message . "\n"));
    }

    public static function printOutV($message)
    {
        if (self::$verboseLevel > 0) {
            self::printOut($message);
        }
    }

    public static function printOutVV($message)
    {
        if (self::$verboseLevel > 1) {
            self::printOut($message);
        }
    }

    public static function printOutVVV($message)
    {
        if (self::$verboseLevel > 2) {
            self::printOut($message);
        }
    }

    public function exitCode($code)
    {
        fwrite(STDOUT, PHP_EOL . PHP_EOL);
        exit($code);
    }

    public function showVersion()
    {
        self::printOut("swagger-to-md " . self::version . " by Nicolas Juhel");
    }

    public function showUsage()
    {
        self::printOut("
Usage: swagger2md [options] swaggerFile");
    }

    public function showHelp()
    {
        self::printOut("
Options:
    --templates={folder}    Specify the folder of the templates to be used
    --tempDir={folder}      Specify the folder for temporary files
    --output={file}         Specify the file to store the generated documentation,
                              if not specify, then print in the stdout the result
    -vvv|--verbose          Prints more verbose message
    -vv                     Prints more verbose message but no message for SwaggerValidator
    -v                      Prints more verbose message only about the building documentation
    --version               Prints the version and exists
    -h|--help               Prints this help message
        ");
    }

    public function checkTemplates($path = null)
    {
        if (defined('PHAR_SWG2MD_ROOT_PATH')) {
            $baseDir = PHAR_SWG2MD_ROOT_PATH;
        }
        elseif (\Phar::running()) {
            $baseDir = null;
        }
        else {
            $baseDir = __DIR__ . DIRECTORY_SEPARATOR;
        }

        if (empty($path)) {
            $path = $baseDir . 'Templates';
        }

        if (\Phar::running()) {
            $pathReal = $path;
        }
        else {
            $pathReal = realpath($path);
        }

        if (!file_exists($pathReal)) {
            self::printOutVV('Given template folder : ' . $path);
            self::printError('The templates folder is not found !');
            self::exitCode(1);
        }

        self::printOutV('Using template folder : ' . $pathReal);
        return $pathReal;
    }

    public static function makeAnchor($title, $suffix = null)
    {
        if ($suffix === true) {
            $suffix = 1;
        }

        return preg_replace('/([^\w-]*)/si', '', str_replace(' ', '-', strtolower($title))) . ($suffix > 0 ? '-' . ((int) $suffix) : '');
    }

    public function extractStored()
    {
        $result = array();
        foreach ($this->suffixObject as $obj) {
            if (is_array($obj) && array_key_exists('file', $obj) && !empty($obj['file'])) {
                $obj['contents'] = file_get_contents($obj['file']);
                unlink($obj['file']);
            }

            if (!empty($obj['contents'])) {
                $result[] = $obj;
            }
        }

        $this->suffixObject = array();
        return $result;
    }

    public function renderTable($name, $anchor, $listKey, $colonsFile, $template, $vars, $store = null)
    {
        if ($store !== false) {
            $file = $this->checkAndMakeObjectFolder();
        }

        if (!is_array($this->suffixObject)) {
            $this->suffixObject = array();
        }

        $colonTitle = $this->getColonArray($colonsFile);

        if (empty($colonTitle)) {
            self::printError('Cannot load colons config for table with this template : ' . $colonsFile);
            return;
        }

        if (empty($vars[$listKey])) {
            self::printError('Cannot rendenr an empty table...');
            return;
        }

        $vars[$listKey] = array_map(function($val) {
            if (!is_array($val) || !array_key_exists(\SwaggerValidator\Common\FactorySwagger::KEY_REQUIRED, $val)) {
                return $val;
            }

            if ($val[\SwaggerValidator\Common\FactorySwagger::KEY_REQUIRED] !== true) {
                unset($val[\SwaggerValidator\Common\FactorySwagger::KEY_REQUIRED]);
            }

            return $val;
        }, $vars[$listKey]);

        $colonTitle = array_map(function($val) use($vars, $listKey) {
            if (empty($val) || !is_array($vars) || !array_key_exists('key', $val)) {
                return;
            }

            if ($val['enabled'] === true) {
                return $val;
            }

            foreach ($vars[$listKey] as $item) {
                if (empty($item) || !is_array($item) || !array_key_exists($val['key'], $item) || is_null($item[$val['key']])) {
                    continue;
                }
                elseif (!is_string($item[$val['key']]) || strlen($item[$val['key']]) > 0) {
                    $val['enabled'] = true;
                    break;
                }
            }

            return $val;
        }, $colonTitle);

        $vars['listColons'] = array_filter($colonTitle, function($val) {
            return $val['enabled'];
        });

        if (!empty($file)) {
            $file .= uniqid('obj_');

            \Swagger2md\Swagger2md::printOutV('Rendering this template : ' . $template);
            file_put_contents($file, $this->twigTpl->render($template, $vars));

            $this->suffixObject[$name] = array(
                'name' => $name,
                'link' => $anchor,
                'file' => $file,
            );
        }
        elseif ($store !== false) {
            \Swagger2md\Swagger2md::printOutV('Rendering this template : ' . $template);
            $this->suffixObject[$name] = array(
                'name'     => $name,
                'link'     => $anchor,
                'contents' => $this->twigTpl->render($template, $vars),
            );
        }
        else {
            \Swagger2md\Swagger2md::printOutV('Rendering this template : ' . $template);
            return $this->twigTpl->render($template, $vars);
        }
    }

    private function checkAndMakeObjectFolder()
    {
        if (empty($this->tempFolder)) {
            return;
        }

        $folder = $this->tempFolder . DIRECTORY_SEPARATOR . 'tmpObject' . DIRECTORY_SEPARATOR;

        if (file_exists($folder)) {
            return $folder;
        }

        try {
            mkdir($folder);
        }
        catch (\Exception $e) {
            self::printError("Error while try to create this folder '{$folder}' : " . $e->getMessage());
            return $this->tempFolder . DIRECTORY_SEPARATOR;
        }

        if (file_exists($folder)) {
            return $folder;
        }

        self::printError("Error while try to create this folder '{$folder}' !");
        return $this->tempFolder . DIRECTORY_SEPARATOR;
    }

    public function getColonArray($fileName)
    {
        if (!file_exists($this->templateFolder)) {
            return null;
        }

        if (!file_exists($this->templateFolder . DIRECTORY_SEPARATOR . $fileName)) {
            return null;
        }

        $configColTitle = explode("\n", str_replace(array("\n\r", "\r\n", "\r"), "\n", file_get_contents($this->templateFolder . DIRECTORY_SEPARATOR . $fileName)));
        $colParamsTitle = array_map(function($val) {
            $colons = explode('|', trim($val));
            $enable = false;

            if (count($colons) < 3) {
                return;
            }

            if (in_array($colons[0], array('name', 'partType'))) {
                $enable = true;
            }

            return array(
                'enabled' => $enable,
                'key'     => $colons[0],
                'title'   => $colons[1],
                'align'   => $colons[2]
            );
        }, $configColTitle);

        return array_filter($colParamsTitle);
    }

    public function renderTemplate($template, $vars)
    {
        \Swagger2md\Swagger2md::printOutV('Rendering this template : ' . $template);
        return $this->twigTpl->render($template, $vars);
    }

}