cleanups
[m6w6/pq-gateway] / lib / pq / Mapper / Map.php
1 <?php
2
3 namespace pq\Mapper;
4
5 use pq\Gateway\Row;
6 use pq\Gateway\Rowset;
7 use pq\Gateway\Table;
8 use pq\Query\Expr;
9
10 class Map implements MapInterface
11 {
12 private $class;
13 private $gateway;
14 private $objects;
15 private $properties;
16
17 function __construct($class, Table $gateway, PropertyInterface ...$properties) {
18 $this->class = $class;
19 $this->gateway = $gateway;
20 $this->properties = $properties;
21 foreach ($properties as $property) {
22 $property->setContainer($this);
23 }
24 $this->objects = new ObjectManager($this);
25 }
26
27 function getClass() {
28 return $this->class;
29 }
30
31 function getObjects() {
32 return $this->objects;
33 }
34
35 /**
36 * @return Table
37 */
38 function getGateway() {
39 return $this->gateway;
40 }
41
42 function getProperties() {
43 return $this->properties;
44 }
45
46 function addProperty(PropertyInterface $property) {
47 $property->setContainer($this);
48 $this->properties[] = $property;
49 return $this;
50 }
51
52 function allOf(Row $row, $refName, &$objects = null) {
53 /* apply objectOf to populate the object cache */
54 return $this->gateway->of($row, $refName)->apply(function($row) use(&$objects) {
55 $objects[] = $this->objects->asObject($row);
56 });
57 }
58
59 function refOf(Row $row, $refName, &$objects = null) {
60 $rid = [];
61 $rel = $row->getTable()->getRelation($this->gateway->getName(), $refName);
62 // FIXME: check if foreign key points to primary key
63 foreach ($rel as $fgn => $col) {
64 $rid[$col] = $row->$fgn->get();
65 }
66 $rid = $this->objects->serializeRowId($rid);
67 if ($this->objects->hasObject($rid)) {
68 $object = $this->objects->getObjectById($rid);
69 $row = $this->objects->getRow($object);
70 $objects[] = $object;
71 $rowset = new Rowset($this->gateway);
72 return $rowset->append($row);
73 }
74 /* apply objectOf to populate the object cache */
75 return $this->gateway->by($row, $refName)->apply(function($row) use(&$objects) {
76 $objects[] = $this->objects->asObject($row);
77 });
78 }
79
80 function relOf(MapInterface $map, $refName) {
81 return $map->getGateway()->getRelation(
82 $this->gateway->getName(), $refName);
83 }
84
85 private function drain(array $deferred, callable $exec) {
86 while ($deferred) {
87 $cb = array_shift($deferred);
88 if (($cb = $exec($cb))) {
89 $deferred[] = $cb;
90 }
91 }
92 }
93
94 function map(Row $row) {
95 $deferred = [];
96 $object = $this->objects->asObject($row);
97 foreach ($this->properties as $property) {
98 if (($cb = $property->read($row, $object))) {
99 $deferred[] = $cb;
100 }
101 }
102 $this->drain($deferred, function(callable $cb) use($row, $object) {
103 return $cb($row, $object);
104 });
105 return $object;
106 }
107
108 function mapAll(Rowset $rows) {
109 $objects = [];
110 foreach ($rows as $row) {
111 $objects[] = $this->map($row);
112 }
113 return $objects;
114 }
115
116 function unmap($object) {
117 $deferred = [];
118 /* @var $row Row */
119 $row = $this->objects->asRow($object);
120 $upd = $this->objects->rowId($row, true);
121 foreach ($this->properties as $property) {
122 if (($cb = $property->write($object, $row))) {
123 $deferred[] = $cb;
124 }
125 }
126 foreach ($this->gateway->getIdentity() as $col) {
127 if (null === $row->$col->get()
128 || ($row->$col->isExpr() && $row->$col->get()->isNull()))
129 {
130 $row->$col = new Expr("DEFAULT");
131 }
132 }
133 if ($row->isDirty()) {
134 if ($upd) {
135 $row->update();
136 } else {
137 $row->create();
138 }
139 }
140 foreach ($this->properties as $property) {
141 if (($cb = $property->read($row, $object))) {
142 $deferred[] = $cb;
143 }
144 }
145 $this->drain($deferred, function($cb) use($object, $row) {
146 return $cb($object, $row);
147 });
148 if ($row->isDirty()) {
149 $row->update();
150 }
151 }
152
153 }