Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 3 - Auto generate BOOLEAN getters and setters - isActive vs getActive

Auto-generate BOOLEAN getters and setters - different output

Symfony3.2.0: php bin/console vs PhpStorm 2016.3

There seems to be a difference in generated code if I use the command line doctrine:generate:entities or use the PhpStorm function Generate - Getters and Setters on a BOOLEAN value within an Entity class.

Example: I have set this private variable, below are 3 examples to generate Getters/Setters, which all give a slightly different output.

/**
 * @var boolean
 * @ORM\Column(name="active", type="boolean")
 */
private $active;

# Generated 'getter' from command line = getActive()
# Generated 'getter' from PhpStorm = isActive()

Console command: php bin/console doctrine:generate:entities MyBundle:MyEntity (note: getActive, return boolean)

/**
 * Set active
 *
 * @param boolean $active
 *
 * @return MyEntity
 */
public function setActive($active)
{
    $this->active = $active;

    return $this;
}

/**
 * Get active
 *
 * @return boolean
 */
public function getActive()
{
    return $this->active;
}

Within PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' enabled) (note: isActive, return bool)

/**
 * @return bool
 */
public function isActive()
{
    return $this->active;
}

/**
 * @param bool $active
 * @return MyEntity
 */
public function setActive($active)
{
    $this->active = $active;
    return $this;
}

and another one: PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' disabled) (note: isActive, return bool, and setActive does not return $this)

/**
 * @return bool
 */
public function isActive()
{
    return $this->active;
}

/**
 * @param bool $active
 */
public function setActive($active)
{
    $this->active = $active;
}

My Questions:

  1. Can the commandline tool doctrine:generate:entities be configured somehow to generate getters for boolean values automatically as is... in stead of 'get...' ? (so that it always generates boolean getter methods as: isActive(), isEnabled(), etc)

  2. I saw some examples/tutorials where the method setActive() did not return $this, so no chaining could be used. Is it best practice to return $this? What would be the preferred way? (Is there a disadvantage when you DO return $this, performance maybe?)

  3. Does the minor difference of the return type within the comment section has any effect on the app (database migrations with the command line or something)? Or are the types bool and boolean handled the same way everywhere in Symfony?

(3. Example)

@return bool (Generated by command line)
vs
@return boolean (Generated by PhpStorm)
like image 299
Develop123 Avatar asked Dec 08 '16 16:12

Develop123


1 Answers

I've played with the code a bit and unfortunately there is no way to generate it differently with the existent setup. All classes are hardcoded and there is no way to override it with command or Symfony settings.

So I've extended generator classes a bit and created extended command that accepts generator as a parameter. I've also created sample generator that created 'is...' methods for setting booleans.

Unfortunately there are some copy-paste from existent classes because it is not possible to extend it.

Answering 2nd question I think that it is more personal preference using fluent interface. I'm old school developer and I'm not used to fluent interface in PHP. I do not see any major performance impact with it.

For the 3rd question. The difference between bool and boolean is that bool is a scalar type declaration while the boolean is a variable type. See the 'Warning' in the documentation. It explains a lot.

<?php
// src/AppBundle/Command/GenerateDoctrineEntityExtendedCommand.php
namespace AppBundle\Command;

use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineEntityCommand;
use Sensio\Bundle\GeneratorBundle\Generator\Generator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class GenerateDoctrineEntityExtendedCommand extends GenerateDoctrineEntityCommand
{
    /** @var Generator */
    private $generator;

    protected function configure()
    {
        parent::configure();
        $this->setName('doctrine:generate:entity:extended');
        $this->setDescription($this->getDescription() . " Allows specifying generator class.");
        $this->addOption('generator', null, InputOption::VALUE_REQUIRED, "The generator class to create entity.", 'Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator');
    }

    protected function initialize(InputInterface $input, OutputInterface $output)
    {
        parent::initialize($input, $output);
        if ($class = $input->getOption('generator')) {
            if (!class_exists($class)) {
                throw new \Exception('Class ' . $class . 'does not exist.');
            }
            $this->generator = new $class($this->getContainer()->get('filesystem'), $this->getContainer()->get('doctrine'));
        }
    }

    protected function createGenerator()
    {
        return $this->generator;
    }
}

DoctrineEntityGenerator replacement:

<?php
// src/AppBundle/Generator/IsDoctrineEntityGenerator.php
namespace AppBundle\Generator;

use Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator;

class IsDoctrineEntityGenerator extends DoctrineEntityGenerator
{
    protected function getEntityGenerator()
    {
        // This is the place where customized entity generator is instantiated instead of default
        $entityGenerator = new IsEntityGenerator();
        $entityGenerator->setGenerateAnnotations(false);
        $entityGenerator->setGenerateStubMethods(true);
        $entityGenerator->setRegenerateEntityIfExists(false);
        $entityGenerator->setUpdateEntityIfExists(true);
        $entityGenerator->setNumSpaces(4);
        $entityGenerator->setAnnotationPrefix('ORM\\');

        return $entityGenerator;
    }
}

EntityGenerator replacement:

<?php
// src/AppBundle/Generator/IsEntityGenerator.php
namespace AppBundle\Generator;

use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\DBAL\Types\Type;

class IsEntityGenerator extends EntityGenerator
{
    protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
    {
        //
        // This is the only line I've added compared to the original method
        //
        $methodPrefix = ($type == 'get' && $typeHint == 'boolean') ? 'is' : $type;
        $methodName = $methodPrefix . Inflector::classify($fieldName);

        $variableName = Inflector::camelize($fieldName);
        if (in_array($type, array("add", "remove"))) {
            $methodName = Inflector::singularize($methodName);
            $variableName = Inflector::singularize($variableName);
        }

        if ($this->hasMethod($methodName, $metadata)) {
            return '';
        }
        $this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);

        $var = sprintf('%sMethodTemplate', $type);
        $template = static::$$var;

        $methodTypeHint = null;
        $types = Type::getTypesMap();
        $variableType = $typeHint ? $this->getType($typeHint) : null;

        if ($typeHint && !isset($types[$typeHint])) {
            $variableType = '\\' . ltrim($variableType, '\\');
            $methodTypeHint = '\\' . $typeHint . ' ';
        }

        $replacements = array(
            '<description>' => ucfirst($type) . ' ' . $variableName,
            '<methodTypeHint>' => $methodTypeHint,
            '<variableType>' => $variableType,
            '<variableName>' => $variableName,
            '<methodName>' => $methodName,
            '<fieldName>' => $fieldName,
            '<variableDefault>' => ($defaultValue !== null) ? (' = ' . $defaultValue) : '',
            '<entity>' => $this->getClassName($metadata)
        );

        $method = str_replace(
            array_keys($replacements),
            array_values($replacements),
            $template
        );

        return $this->prefixCodeWithSpaces($method);
    }
}

So that's I'm afraid the only option for what you want so far.

like image 183
Stepashka Avatar answered Nov 19 '22 01:11

Stepashka