Passed
Branch dev_2x (3e8772)
by Adrian
01:42
created

OneToManyObserver::observeBaseEntity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 39
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 29
c 1
b 0
f 0
dl 0
loc 39
rs 9.456
cc 2
nc 2
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Sirius\Orm\CodeGenerator\Observer\Relation;
5
6
use Nette\PhpGenerator\ClassType;
7
use Sirius\Orm\Blueprint\Mapper;
8
use Sirius\Orm\Blueprint\Relation;
9
use Sirius\Orm\Blueprint\Relation\OneToMany;
10
use Sirius\Orm\CodeGenerator\Observer\Base;
11
use Sirius\Orm\Collection\Collection;
12
use Sirius\Orm\Contract\Relation\ToManyInterface;
13
use Sirius\Orm\Helpers\Inflector;
14
use Sirius\Orm\Helpers\Str;
15
16
class OneToManyObserver extends Base implements ToManyInterface
17
{
18
19
    /**
20
     * @var OneToMany
21
     */
22
    protected $relation;
23
24
    public function with(Relation $relation)
25
    {
26
        $clone           = clone($this);
27
        $clone->relation = $relation;
28
29
        return $clone;
30
    }
31
32
    public function observe(string $key, $object)
33
    {
34
        if ($key == $this->relation->getMapper()->getName() . '_base_entity') {
35
            return $this->observeBaseEntity($object);
36
        }
37
38
        return $object;
39
    }
40
41
    public function __toString()
42
    {
43
        return sprintf(
44
            'Observer for relation %s for mapper %s',
45
            $this->relation->getName(),
46
            $this->relation->getMapper()->getName()
47
        );
48
    }
49
50
    public function observeBaseEntity(ClassType $class)
51
    {
52
        $this->addAttributeToConstructor($class);
53
54
        $mapper        = $this->relation->getMapper();
55
        $name          = $this->relation->getName();
56
        $foreignMapper = $mapper->getOrm()->getMapper($this->relation->getForeignMapper());
57
        $type          = $foreignMapper->getEntityNamespace()
58
                         . '\\' . $foreignMapper->getEntityClass();
59
60
        /** @scrutinizer ignore-deprecated */ $class->getNamespace()->addUse(Collection::class);
61
        /** @scrutinizer ignore-deprecated */ $class->getNamespace()->addUse($type, null, $type);
62
63
        if ($mapper->getEntityStyle() === Mapper::ENTITY_STYLE_PROPERTIES) {
64
            $class->addComment(sprintf('@property %s[]|Collection $%s', $type, $name));
65
        } else {
66
            $setter = $class->addMethod(Str::methodName($name, 'set'));
67
            $setter->setVisibility(ClassType::VISIBILITY_PUBLIC);
68
            $setter->addParameter('value')
69
                   ->setType('Collection');
70
            $setter->setBody('$this->set(\'' . $name . '\', $value);');
71
72
            $getter = $class->addMethod(Str::methodName($name, 'get'));
73
            $getter->setVisibility(ClassType::VISIBILITY_PUBLIC);
74
            $getter->setBody('return $this->get(\'' . $name . '\');');
75
            $getter->setReturnType('Collection');
76
            $getter->setComment(sprintf('@return Collection|%s[]', $type));
77
        }
78
79
        $singular = Inflector::singularize($name);
80
        $adder    = $class->addMethod(Str::methodName($singular, 'add'));
81
        $adder->setVisibility(ClassType::VISIBILITY_PUBLIC);
82
        $adder->addParameter($singular)
83
              ->setType($type);
84
        $adder->setBody(sprintf('$this->get(\'%s\')->add($%s);', $name, $singular));
85
86
        $class = $this->addAggregates($class);
87
88
        return $class;
89
    }
90
91
    private function addAttributeToConstructor(ClassType $class)
92
    {
93
        $name = $this->relation->getName();
94
95
        $constructor = $class->getMethod('__construct');
96
//        $constructor->addBody(rtrim('
97
//// this is a fail-safe procedure that will be executed
98
//// only when you use `new Entity()` instead of `$mapper->newEntity()`
99
//// ALWAYS try to use `$mapper->newEntity()`
100
//if (!isset($this->attributes[\'' . $name . '\'])) {
101
//    $this->attributes[\'' . $name . '\'] = new Collection;
102
//}
103
//        '));
104
    }
105
106
    private function addAggregates(ClassType $class)
107
    {
108
        $mapper        = $this->relation->getMapper();
109
        $aggregates = $this->relation->getAggregates();
110
111
        foreach ($aggregates as $name => $aggregate) {
112
            if ($mapper->getEntityStyle() === Mapper::ENTITY_STYLE_PROPERTIES) {
113
                $class->addComment(sprintf('@property mixed $%s', $name));
114
            } else {
115
                $getter = $class->addMethod(Str::methodName($name, 'get'));
116
                $getter->setVisibility(ClassType::VISIBILITY_PUBLIC);
117
                $getter->setBody('return $this->get(\'' . $name . '\');');
118
            }
119
        }
120
121
        return $class;
122
    }
123
}
124