DoctrineCrudGenerator   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
c 1
b 0
f 0
lcom 1
cbo 4
dl 0
loc 163
rs 10
ccs 58
cts 58
cp 1

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A generate() 0 22 3
B generateControllerClass() 0 28 2
A generateTestClass() 0 10 1
A canWriteToFile() 0 4 2
A getIdentifierType() 0 11 3
A getEntityIdentifier() 0 4 1
A getRequirementRegex() 0 11 3
1
<?php
2
3
namespace Pgs\RestfonyBundle\Generator;
4
5
use Doctrine\ORM\Mapping\ClassMetadataInfo;
6
use InvalidArgumentException;
7
use Pgs\RestfonyBundle\Generator\Helper\BundleStructureHelper;
8
use Sensio\Bundle\GeneratorBundle\Generator\Generator;
9
use Symfony\Component\Filesystem\Filesystem;
10
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
11
use RuntimeException;
12
13
class DoctrineCrudGenerator extends Generator
14
{
15
    /**
16
     * @var Filesystem
17
     */
18
    protected $filesystem;
19
20
    /**
21
     * @var BundleStructureHelper
22
     */
23
    protected $helper;
24
25
    /** @var BundleInterface */
26
    protected $bundle;
27
28
    protected $entity;
29
    protected $metadata;
30
    protected $actions;
31
32
    /**
33
     * Constructor.
34
     *
35
     * @param Filesystem $filesystem A Filesystem instance
36
     * @param BundleInterface $bundle
37
     * @param string $entity
38
     */
39 5
    public function __construct(Filesystem $filesystem, BundleInterface $bundle, $entity)
40
    {
41 5
        $this->filesystem = $filesystem;
42 5
        $this->helper = new BundleStructureHelper($bundle, $entity);
43 5
    }
44
45
    /**
46
     * Generate the CRUD controller.
47
     *
48
     * @param BundleInterface   $bundle           A bundle object
49
     * @param string            $entity           The entity relative class name
50
     * @param ClassMetadataInfo $metadata         The entity class metadata
51
     * @param array             $needWriteActions Whether or not to generate write actions
52
     * @param $forceOverwrite
53
     */
54 5
    public function generate(
55
        BundleInterface $bundle,
56
        $entity,
57
        ClassMetadataInfo $metadata,
58
        $needWriteActions,
59
        $forceOverwrite
60
    ) {
61 5
        $this->actions = $needWriteActions
62 3
            ? ['cget', 'get', 'post', 'put', 'patch', 'delete', 'new', 'edit']
63 2
            : ['cget', 'get'];
64
65 5
        if (count($metadata->getIdentifier()) !== 1) {
66 1
            throw new RuntimeException('CRUD generator does not support entities with multiple or no primary keys.');
67
        }
68
69 4
        $this->entity   = $entity;
70 4
        $this->bundle   = $bundle;
71 4
        $this->metadata = $metadata;
72
73 4
        $this->generateControllerClass($forceOverwrite);
74 3
        $this->generateTestClass();
75 3
    }
76
77
    /**
78
     * Generates the controller class only.
79
     *
80
     * @param bool $forceOverwrite
81
     */
82 4
    protected function generateControllerClass($forceOverwrite)
83
    {
84 4
        $metadata = $this->metadata;
85
86 4
        $target = $this->helper->getControllerFullFilename();
0 ignored issues
show
Documentation Bug introduced by
The method getControllerFullFilename does not exist on object<Pgs\RestfonyBundl...\BundleStructureHelper>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
87
88 4
        $parts = explode('\\', $this->entity);
89 4
        array_pop($parts);
90 4
        $entityNamespace = implode('\\', $parts);
91
92 4
        if (!$this->canWriteToFile($target, $forceOverwrite)) {
93 1
            throw new \RuntimeException('Unable to generate the controller as it already exists.');
94
        }
95
96 3
        $idType = $this->getIdentifierType($metadata);
97
98 3
        $this->renderFile('controller/controller.php.twig', $target, array(
99 3
            'actions'           => $this->actions,
100 3
            'entity'            => $this->entity,
101 3
            'namespace'         => $this->bundle->getNamespace(),
102 3
            'entity_namespace'  => $entityNamespace,
103 3
            'entity_identifier_type' => $idType,
104 3
            'entity_identifier'      => $this->getEntityIdentifier($metadata),
105 3
            'requirement_regex'      => $this->getRequirementRegex($idType),
106
            'document' => true,
107 3
            'form_type' => $this->bundle->getNamespace()."\\Form\\Type\\".$this->entity."Type.php",
108
        ));
109 3
    }
110
111
    /**
112
     * Generates the functional test class only.
113
     */
114 3
    protected function generateTestClass()
115
    {
116 3
        $target = $this->helper->getTestsDirname() . '/Controller/' . $this->helper->getControllerClass() . 'Test.php';
0 ignored issues
show
Documentation Bug introduced by
The method getTestsDirname does not exist on object<Pgs\RestfonyBundl...\BundleStructureHelper>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Documentation Bug introduced by
The method getControllerClass does not exist on object<Pgs\RestfonyBundl...\BundleStructureHelper>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
117
118 3
        $this->renderFile('controller/controller-test.php.twig', $target, array(
119 3
            'entity'            => $this->entity,
120 3
            'namespace'         => $this->bundle->getNamespace(),
121 3
            'actions'           => $this->actions,
122
        ));
123 3
    }
124
125 3
    protected function canWriteToFile($file, $forceOverwrite)
126
    {
127 3
        return !file_exists($file) || $forceOverwrite;
128
    }
129
130
    /**
131
     * @param ClassMetadataInfo $metadata
132
     *
133
     * @throws \InvalidArgumentException
134
     *
135
     * @return string
136
     */
137 3
    private function getIdentifierType(ClassMetadataInfo $metadata)
138
    {
139 3
        $identifier = array_values($metadata->getIdentifier())[0];
140 3
        foreach ($metadata->fieldMappings as $field) {
141 3
            if ($field['fieldName'] === $identifier) {
142 3
                return $field['type'];
143
            }
144
        }
145
146 1
        return '';
147
    }
148
149
    /**
150
     * @param ClassMetadataInfo $metadata
151
     *
152
     * @return mixed
153
     */
154 3
    private function getEntityIdentifier(ClassMetadataInfo $metadata)
155
    {
156 3
        return array_values($metadata->getIdentifier())[0];
157
    }
158
159
    /**
160
     * @param string $idType
161
     *
162
     * @return string
163
     */
164 3
    private function getRequirementRegex($idType)
165
    {
166
        switch ($idType) {
167 3
            case 'string':
168 1
                return '\w+';
169 2
            case 'integer':
170 1
                return '\d+';
171
            default:
172 1
                return '';
173
        }
174
    }
175
}
176