Completed
Push — master ( 1af4f5...caaac4 )
by Andreas
03:43
created

classgenerator::write_parent_getter()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 8
nop 1
dl 0
loc 18
ccs 14
cts 14
cp 1
crap 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
4
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
6
 */
7
8
namespace midgard\portable;
9
10
use midgard\portable\mgdschema\manager;
11
use midgard\portable\mgdschema\type;
12
use midgard\portable\mgdschema\mixin;
13
use midgard\portable\mgdschema\property;
14
use midgard\portable\mgdschema\translator;
15
16
class classgenerator
17
{
18
    /**
19
     *
20
     * @var string
21
     */
22
    private $output;
23
24
    /**
25
     *
26
     * @var string
27
     */
28
    private $filename;
29
30
    /**
31
     *
32
     * @var manager
33
     */
34
    private $manager;
35
36
    /**
37
     *
38
     * @var boolean
39
     */
40
    private $dev_mode = false;
41
42 11
    public function __construct(manager $manager, $filename, $dev_mode = false)
43
    {
44 11
        $this->manager = $manager;
45 11
        $this->filename = $filename;
46 11
        $this->dev_mode = $dev_mode;
47 11
    }
48
49 11
    private function add_line($line)
50
    {
51 11
        $this->output .= $line;
52 11
        if ($this->dev_mode) {
53 10
            $this->output .= "\n";
54 10
        } else {
55 1
            $this->output .= ' ';
56
        }
57 11
    }
58
59 11
    public function write($namespace = '')
60
    {
61 11
        if (file_exists($this->filename)) {
62 9
            unlink($this->filename);
63 9
        }
64
65 11
        $types = $this->manager->get_types();
66
        uasort($types, function ($a, $b) {
67 11
            if (   !empty($a->extends)
68 11
                && !empty($b->extends)) {
69 11
                return strnatcmp($a->extends, $b->extends);
70
            } elseif (!empty($a->extends)) {
71
                return -1;
72
            } elseif (!empty($b->extends)) {
73
                return 1;
74
            }
75
            return 0;
76 11
        });
77
78 11
        $this->add_line('<?php');
79
80 11
        if (!empty($namespace)) {
81 11
            $this->add_line('namespace ' . $namespace . ';');
82 11
            $this->add_line('use midgard\\portable\\api\\object as midgard_object;');
83 11
            $this->add_line('use midgard_metadata;');
84 11
            $this->add_line('use midgard_datetime;');
85 11
        }
86 11
        $this->add_line('use midgard\\portable\\api\\user as base_user;');
87 11
        $this->add_line('use midgard\\portable\\api\\person as base_person;');
88 11
        $this->add_line('use midgard\\portable\\api\\parameter as base_parameter;');
89 11
        $this->add_line('use midgard\\portable\\api\\repligard as base_repligard;');
90 11
        $this->add_line('use midgard\\portable\\api\\attachment as base_attachment; ');
91
92 11
        foreach ($types as $type) {
93 11
            $this->convert_type($type);
94 11
        }
95
96 11
        $this->register_aliases($namespace);
97
98
        //todo: midgard_blob special handling
99
100 11
        file_put_contents($this->filename, $this->output);
101 11
    }
102
103 11
    private function register_aliases($namespace)
104
    {
105 11
        $prefix = $this->get_class_prefix($namespace);
106
107 11
        foreach ($this->manager->get_types() as $type) {
108 View Code Duplication
            if (   $prefix !== ''
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109 11
                && !class_exists($type->name)) {
110 1
                $this->add_line('class_alias( "' . $prefix . $type->name . '", "' . $type->name . '");');
111 1
            }
112 11
        }
113
114 11
        foreach ($this->manager->get_inherited_mapping() as $child => $parent) {
115 5
            $this->add_line('class_alias( "' . $prefix . $parent . '", "' . $prefix . $child . '");');
116 View Code Duplication
            if (   $prefix !== ''
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
117 5
                && !class_exists($child)) {
118 1
                $this->add_line('class_alias( "' . $prefix . $parent . '", "' . $child . '");');
119 1
            }
120 11
        }
121 11
    }
122
123 11
    private function get_class_prefix($namespace)
124
    {
125 11
        if ($namespace === '') {
126
            return '';
127
        }
128 11
        return str_replace('\\', '\\\\', $namespace) . '\\\\';
129
    }
130
131 11
    private function convert_type(type $type)
132
    {
133 11
        $this->begin_class($type);
134 11
        $objects = $this->write_properties($type);
135
136 11
        $this->write_constructor($objects);
137
138 11
        $this->write_parent_getter($type);
139
140 11
        $this->end_class();
141 11
    }
142
143 11
    private function write_properties(type $type)
144
    {
145 11
        $objects = array();
146 11
        foreach ($type->get_mixins() as $name => $mixin) {
147 11
            $this->add_line(' protected $' . $name . ';');
148 11
        }
149
150 11
        foreach ($type->get_properties() as $name => $property) {
151 11
            if ($name == 'guid') {
152 11
                continue;
153
            }
154 11
            $line = ' protected $' . $name;
155 11
            $default = null;
156 11
            switch (translator::to_constant($property->type)) {
157 11
                case translator::TYPE_BOOLEAN:
158 11
                    $default = 'false';
159 11
                    break;
160 11
                case translator::TYPE_FLOAT:
161 9
                    $default = '0.0';
162 9
                    break;
163 11
                case translator::TYPE_UINT:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
164 11
                    if ($name == $type->primaryfield) {
165
                        // no default value for identifier, because otherwise, Doctrine will think it's a detached entity
166 11
                        break;
167
                    }
168 11
                case translator::TYPE_INT:
169 11
                    $default = '0';
170 11
                    break;
171 11
                case translator::TYPE_GUID:
172 11
                case translator::TYPE_STRING:
173 11
                case translator::TYPE_LONGTEXT:
174 11
                    $default = "''";
175 11
                    break;
176 11
                case translator::TYPE_TIMESTAMP:
177 11
                    $objects[$name] = 'new midgard_datetime("0001-01-01 00:00:00")';
178 11
                    break;
179 11
            }
180
            if (   $default !== null
181
                   // we need to skip working links because in this case, Doctrine expects objects as values
182 11
                && (   !$property->link
183 11
                    || $this->manager->resolve_targetclass($property) === false)) {
184 11
                $line .= ' = ' . $default;
185 11
            }
186 11
            $this->add_line($line . ';');
187 11
        }
188 11
        return $objects;
189
    }
190
191 11
    private function write_constructor(array $objects)
192
    {
193 11
        if (!empty($objects)) {
194 11
            $this->add_line('public function __construct($id = null) {');
195 11
            foreach ($objects as $name => $code) {
196 11
                $this->add_line('$this->' . $name . ' = ' . $code . ';');
197 11
            }
198 11
            $this->add_line('parent::__construct($id);');
199 11
            $this->add_line('}');
200 11
        }
201 11
    }
202
203 11
    private function write_parent_getter($type)
204
    {
205 11
        $candidates = array();
206
207 11
        if (!empty($type->upfield)) {
208 11
            $candidates[] = $type->upfield;
209 11
        }
210 11
        if (!empty($type->parentfield)) {
211 11
            $candidates[] = $type->parentfield;
212 11
        }
213 11
        if (empty($candidates)) {
214 11
            return;
215
        }
216
217 11
        $this->add_line('public function get_parent() {');
218 11
        $this->add_line(' return $this->load_parent(' . var_export($candidates, true) . ');');
219 11
        $this->add_line('}');
220 11
    }
221
222 11
    private function begin_class(type $type)
223
    {
224 11
        $this->add_line('class ' . $type->name . ' extends ' . $type->extends);
225 11
        $mixins = $type->get_mixins();
226 11
        $interfaces = array_filter(array_map(function ($name) {
227 11
            if (interface_exists('\\midgard\\portable\\storage\\' . $name . '\\entity')) {
228 11
                return '\\midgard\\portable\\storage\\' . $name . '\\entity';
229
            }
230
            return false;
231 11
        }, array_keys($mixins)));
232
233 11
        if (count($interfaces) > 0) {
234 11
            $this->add_line(' implements ' . implode(', ', $interfaces));
235 11
        }
236 11
        $this->add_line('{');
237 11
    }
238
239 11
    private function end_class()
240
    {
241 11
        $this->add_line('}');
242 11
    }
243
}
244