Completed
Branch master (3b8125)
by
unknown
01:10
created

TestClassManager::getNamespaceWithoutName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace HelloWordPl\SimpleEntityGeneratorBundle\Lib\Items;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Exception;
7
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\DumpableInterface;
8
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\RenderableInterface;
9
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\StructureWithMethodsInterface;
10
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Tools;
11
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Traits\TemplateTrait;
12
use Symfony\Component\Validator\Constraints as Assert;
13
14
/**
15
 * Decorator for Class Manager to generate Test Class
16
 *
17
 * @author Sławomir Kania <[email protected]>
18
 */
19
class TestClassManager implements RenderableInterface, DumpableInterface, StructureWithMethodsInterface
20
{
21
22
    use TemplateTrait;
23
24
    /**
25
     * @Assert\NotNull(message="Test class has to know about class for testing")
26
     * @Assert\Valid()
27
     * @var ClassManager
28
     */
29
    private $classManager = null;
30
31
    /**
32
     * @var ArrayCollection
33
     * @Assert\NotNull(message="Method collection can not be empty!")
34
     * @Assert\Valid()
35
     */
36
    private $methods = null;
37
38
    /**
39
     * Construct
40
     *
41
     * @param ClassManager $classManager
42
     */
43
    public function __construct(ClassManager $classManager)
44
    {
45
        $this->setClassManager($classManager);
46
        $this->setMethods(new ArrayCollection());
47
    }
48
49
    /**
50
     * Get Base ClassManager
51
     *
52
     * @return ClassManager
53
     */
54
    public function getClassManager()
55
    {
56
        return $this->classManager;
57
    }
58
59
    /**
60
     * Set Base ClassManager
61
     *
62
     * @param ClassManager $classManager
63
     */
64
    public function setClassManager(ClassManager $classManager)
65
    {
66
        $this->classManager = $classManager;
67
    }
68
69
    /**
70
     * Return collection of methods
71
     *
72
     * @return ArrayCollection
73
     */
74
    public function getMethods()
75
    {
76
        return $this->methods;
77
    }
78
79
    /**
80
     * Set collection of methods
81
     *
82
     * @param ArrayCollection $methods
83
     * @return InterfaceManager
84
     */
85
    public function setMethods(ArrayCollection $methods)
86
    {
87
        $this->methods = $methods;
88
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (HelloWordPl\SimpleEntity...\Items\TestClassManager) is incompatible with the return type declared by the interface HelloWordPl\SimpleEntity...dsInterface::setMethods of type HelloWordPl\SimpleEntity...rfaces\InterfaceManager.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
89
    }
90
91
    /**
92
     * Return comment for class/interface
93
     *
94
     * @return string
95
     */
96
    public function getComment()
97
    {
98
        return sprintf("Test for %s", $this->getClassManager()->getNamespace());
99
    }
100
101
    /**
102
     * Return namespace without name - for createing directory
103
     *
104
     * @return string
105
     * @throws Exception
106
     */
107
    public function getDirectory()
108
    {
109
        return str_replace("\\", "/", $this->getNamespaceWithoutName());
110
    }
111
112
    /**
113
     * Return name of class/interface from namespace
114
     *
115
     * @return string
116
     * @throws Exception
117
     */
118
    public function getName()
119
    {
120
        return $this->getClassManager()->getName()."Test";
121
    }
122
123
    /**
124
     * Return namespace
125
     *
126
     * @return string
127
     */
128
    public function getNamespace()
129
    {
130
        return $this->appendTestDirectory(sprintf("%s\%s", $this->getClassManager()->getNamespaceWithoutName(), $this->getName()));
131
    }
132
133
    /**
134
     * Return namespace without name - for rendering namespace in class
135
     *
136
     * @return string
137
     * @throws Exception
138
     */
139
    public function getNamespaceWithoutName()
140
    {
141
        return $this->appendTestDirectory($this->getClassManager()->getNamespaceWithoutName());
142
    }
143
144
    /**
145
     * Return namespace without name - for rendering namespace in class
146
     *
147
     * @return string
148
     * @throws Exception
149
     */
150
    public function getNamespaceWithoutNameAndBackslashPrefix()
151
    {
152
        return Tools::removeBackslashPrefixFromNamespace(Tools::getNamespaceWithoutName($this->getNamespace()));
153
    }
154
155
    /**
156
     * Return set of tags used in template
157
     *
158
     * @return array
159
     */
160
    public function getTemplateTags()
161
    {
162
        return [
163
            self::TAG_NAMESPACE,
164
            self::TAG_COMMENT,
165
            self::TAG_NAME,
166
            self::TAG_CLASS,
167
            self::TAG_METHODS,
168
            self::TAG_TEST_OBJECT_TYPE,
169
            self::TAG_METHOD_BODY,
170
        ];
171
    }
172
173
    /**
174
     * Append \Test\ part to namespace
175
     *
176
     * @param string $namespace
177
     * @return string
178
     * @throws Exception
179
     */
180
    protected function appendTestDirectory($namespace)
181
    {
182
        if (false === Tools::isNamespaceValid($namespace)) {
183
            throw new Exception(sprintf("Invalid namespace: %s", $namespace));
184
        }
185
186
        $namespace = Tools::removeBackslashPrefixFromNamespace($namespace);
187
        $namespaceParts = explode("\\", $namespace);
188
        $firstParts = array_slice($namespaceParts, 0, 1);
189
        $secondParts = array_slice($namespaceParts, 1, count($namespaceParts) - 1);
190
191
        $newNamespaceParts = [];
192
        $newNamespaceParts = array_merge($newNamespaceParts, $firstParts);
193
        $newNamespaceParts[] = "Tests";
194
        $newNamespaceParts = array_merge($newNamespaceParts, $secondParts);
195
196
        return "\\".implode("\\", $newNamespaceParts);
197
    }
198
}
199