Lullabot/mpx-php

View on GitHub
command/src/CreateDataServiceClassCommand.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace Lullabot\Mpx\Command;

use GuzzleHttp\Psr7\Uri;
use Lullabot\Mpx\DataService\DateTime\DateTimeFormatInterface;
use Lullabot\Mpx\DataService\DateTime\NullDateTime;
use Nette\PhpGenerator\PhpNamespace;
use Psr\Http\Message\UriInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CreateDataServiceClassCommand extends ClassGeneratorBase
{
    protected function configure()
    {
        $this->setName('mpx:create-data-service')
            ->setDescription('This command helps to create a data service class from a CSV via stdin.')
            ->setHelp("This command generates a PHP class from a CSV copied from MPX's documentation. Create the CSV by copying the fields table from an object and converting it to a CSV using a spreadsheet. The CSV is read through STDIN. \n\nhttps://docs.theplatform.com/help/media-media-object is a good example of the table this command expects.")
            ->addUsage('Lullabot\Mpx\DataService\Media\Media < command/csv/media-object.csv')
            ->addArgument('fully-qualified-class-name', \Symfony\Component\Console\Input\InputArgument::REQUIRED, 'The fully-qualified class name to generate. Do not include the leading slash, and wrap the class name in single-quotes to handle shell escaping.');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $handle = fopen('php://stdin', 'rb');
        $index = 0;

        $output->write("<?php\n\n");

        // Extract the containing class namespace and the class name.
        $parts = explode('\\', $input->getArgument('fully-qualified-class-name'));
        $namespace = new PhpNamespace(implode('\\', \array_slice($parts, 0, -1)));
        $class = $namespace->addClass(end($parts));

        // Loop over each row, which corresponds to each property.
        while (!feof($handle)) {
            $row = fgetcsv($handle);
            if (0 == $index) {
                ++$index;
                continue;
            }
            ++$index;

            [$field_name, $attributes, $data_type, $description] = $row;
            if (empty($description)) {
                continue;
            }

            if (strrpos((string) $description, '.') !== (\strlen((string) $description) - 1)) {
                $description .= '.';
            }

            // Map MPX documentation datatypes to PHP datatypes.
            foreach (static::TYPE_MAP as $search => $replace) {
                $data_type = str_replace($search, $replace, (string) $data_type);
            }

            // Add the protected property.
            $property = $class->addProperty($field_name);
            $property->setVisibility('protected');
            $property->setComment($description);

            $property->addComment('');
            $property->addComment('@var '.$data_type);
            if ($this->isCollectionType($data_type)) {
                $property->setValue([]);
            }

            // Add a get method for the property.
            $get = $class->addMethod('get'.ucfirst($property->getName()));
            $get->setVisibility('public');
            $get->addComment('Returns '.lcfirst((string) $description));
            $get->addComment('');
            $get->addComment('@return '.$data_type);

            // If the property is a typed array, PHP will only let us use
            // array in the return typehint.
            $this->setReturnType($get, $data_type);

            if ($data_type == '\\'.DateTimeFormatInterface::class) {
                $namespace->addUse(NullDateTime::class);
                $get->addBody('if (!$this->'.$field_name.') {');
                $get->addBody('    return new NullDateTime();');
                $get->addBody('}');
            }

            if ($data_type == '\\'.UriInterface::class) {
                $namespace->addUse(Uri::class);
                $get->addBody('if (!$this->'.$field_name.') {');
                $get->addBody('    return new Uri();');
                $get->addBody('}');
            }

            $get->addBody('return $this->'.$field_name.';');

            // Add a set method for the property.
            $set = $class->addMethod('set'.ucfirst($property->getName()));
            $set->setVisibility('public');
            $set->addComment('Set '.lcfirst((string) $description));
            $set->addComment('');
            $set->addComment('@param '.$data_type.' $'.$field_name);
            $parameter = $set->addParameter($field_name);
            $this->setTypeHint($parameter, $data_type);
            $set->addBody('$this->'.$field_name.' = '.'$'.$field_name.';');
        }

        $output->write((string) $namespace);
        fclose($handle);
    }
}