1<?php
2
3/*
4 * This file is part of the Prophecy.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6 *     Marcello Duarte <marcello.duarte@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Prophecy\Doubler\Generator\Node;
13
14use Prophecy\Exception\Doubler\MethodNotExtendableException;
15use Prophecy\Exception\InvalidArgumentException;
16
17/**
18 * Class node.
19 *
20 * @author Konstantin Kudryashov <ever.zet@gmail.com>
21 */
22class ClassNode
23{
24    private $parentClass = 'stdClass';
25    private $interfaces  = array();
26    private $properties  = array();
27    private $unextendableMethods = array();
28
29    /**
30     * @var MethodNode[]
31     */
32    private $methods     = array();
33
34    public function getParentClass()
35    {
36        return $this->parentClass;
37    }
38
39    /**
40     * @param string $class
41     */
42    public function setParentClass($class)
43    {
44        $this->parentClass = $class ?: 'stdClass';
45    }
46
47    /**
48     * @return string[]
49     */
50    public function getInterfaces()
51    {
52        return $this->interfaces;
53    }
54
55    /**
56     * @param string $interface
57     */
58    public function addInterface($interface)
59    {
60        if ($this->hasInterface($interface)) {
61            return;
62        }
63
64        array_unshift($this->interfaces, $interface);
65    }
66
67    /**
68     * @param string $interface
69     *
70     * @return bool
71     */
72    public function hasInterface($interface)
73    {
74        return in_array($interface, $this->interfaces);
75    }
76
77    public function getProperties()
78    {
79        return $this->properties;
80    }
81
82    public function addProperty($name, $visibility = 'public')
83    {
84        $visibility = strtolower($visibility);
85
86        if (!in_array($visibility, array('public', 'private', 'protected'))) {
87            throw new InvalidArgumentException(sprintf(
88                '`%s` property visibility is not supported.', $visibility
89            ));
90        }
91
92        $this->properties[$name] = $visibility;
93    }
94
95    /**
96     * @return MethodNode[]
97     */
98    public function getMethods()
99    {
100        return $this->methods;
101    }
102
103    public function addMethod(MethodNode $method, $force = false)
104    {
105        if (!$this->isExtendable($method->getName())){
106            $message = sprintf(
107                'Method `%s` is not extendable, so can not be added.', $method->getName()
108            );
109            throw new MethodNotExtendableException($message, $this->getParentClass(), $method->getName());
110        }
111
112        if ($force || !isset($this->methods[$method->getName()])) {
113            $this->methods[$method->getName()] = $method;
114        }
115    }
116
117    public function removeMethod($name)
118    {
119        unset($this->methods[$name]);
120    }
121
122    /**
123     * @param string $name
124     *
125     * @return MethodNode|null
126     */
127    public function getMethod($name)
128    {
129        return $this->hasMethod($name) ? $this->methods[$name] : null;
130    }
131
132    /**
133     * @param string $name
134     *
135     * @return bool
136     */
137    public function hasMethod($name)
138    {
139        return isset($this->methods[$name]);
140    }
141
142    /**
143     * @return string[]
144     */
145    public function getUnextendableMethods()
146    {
147        return $this->unextendableMethods;
148    }
149
150    /**
151     * @param string $unextendableMethod
152     */
153    public function addUnextendableMethod($unextendableMethod)
154    {
155        if (!$this->isExtendable($unextendableMethod)){
156            return;
157        }
158        $this->unextendableMethods[] = $unextendableMethod;
159    }
160
161    /**
162     * @param string $method
163     * @return bool
164     */
165    public function isExtendable($method)
166    {
167        return !in_array($method, $this->unextendableMethods);
168    }
169}
170