1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace WyriHaximus\React\Cake\Orm; |
4
|
|
|
|
5
|
|
|
use Cake\ORM\Query; |
6
|
|
|
use Cake\ORM\TableRegistry; |
7
|
|
|
use Doctrine\Common\Annotations\AnnotationReader; |
8
|
|
|
use phpDocumentor\Reflection\DocBlock; |
9
|
|
|
use phpDocumentor\Reflection\DocBlockFactory; |
10
|
|
|
use React\Promise\PromiseInterface; |
11
|
|
|
use WyriHaximus\React\Cake\Orm\Annotations\Async; |
12
|
|
|
use WyriHaximus\React\Cake\Orm\Annotations\Sync; |
13
|
|
|
|
14
|
|
|
trait AsyncTable |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* @var Pool |
18
|
|
|
*/ |
19
|
|
|
private $pool; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var string |
23
|
|
|
*/ |
24
|
|
|
private $tableName; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var AnnotationReader |
28
|
|
|
*/ |
29
|
|
|
private $annotationReader; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var \ReflectionClass |
33
|
|
|
*/ |
34
|
|
|
private $reflectionClass; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @param Pool $pool |
38
|
|
|
* @param string $tableName |
39
|
|
|
* @param mixed $tableClass |
40
|
|
|
*/ |
41
|
|
|
public function setUpAsyncTable(Pool $pool, $tableName, $tableClass) |
42
|
|
|
{ |
43
|
|
|
$this->pool = $pool; |
44
|
|
|
$this->tableName = $tableName; |
45
|
|
|
$this->annotationReader = new AnnotationReader(); |
46
|
|
|
$this->reflectionClass = new \ReflectionClass($tableClass); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @param $function |
51
|
|
|
* @param array $arguments |
52
|
|
|
* @return PromiseInterface |
53
|
|
|
*/ |
54
|
|
|
protected function callAsyncOrSync($function, $arguments) |
55
|
|
|
{ |
56
|
|
|
if ($this->pool === null) { |
57
|
|
|
return (new $this->tableName())->$function(...$arguments); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
if ( |
61
|
|
|
$this->returnsQuery($function) || |
62
|
|
|
$this->hasMethodAnnotation($function, Async::class) || |
63
|
|
|
( |
64
|
|
|
$this->hasClassAnnotation(Async::class) && |
65
|
|
|
$this->hasNoMethodAnnotation($function) |
66
|
|
|
) || |
67
|
|
|
strpos(strtolower($function), 'save') === 0 || |
68
|
|
|
strpos(strtolower($function), 'find') === 0 || |
69
|
|
|
strpos(strtolower($function), 'fetch') === 0 || |
70
|
|
|
strpos(strtolower($function), 'retrieve') === 0 |
71
|
|
|
) { |
72
|
|
|
return $this->callAsync($function, $arguments); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
return $this->callSync($function, $arguments); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param $function |
80
|
|
|
* @param array $arguments |
81
|
|
|
* @return PromiseInterface |
82
|
|
|
*/ |
83
|
|
|
private function callSync($function, array $arguments = []) |
84
|
|
|
{ |
85
|
|
|
$table = TableRegistry::get($this->tableName); |
|
|
|
|
86
|
|
|
if (isset(class_uses($table)[TableRegistryTrait::class])) { |
87
|
|
|
$table->setRegistry(AsyncTableRegistry::class); |
|
|
|
|
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return \React\Promise\resolve( |
91
|
|
|
call_user_func_array( |
92
|
|
|
[ |
93
|
|
|
$table, |
94
|
|
|
$function, |
95
|
|
|
], |
96
|
|
|
$arguments |
97
|
|
|
) |
98
|
|
|
); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* @param $function |
103
|
|
|
* @param array $arguments |
104
|
|
|
* @return PromiseInterface |
105
|
|
|
*/ |
106
|
|
|
private function callAsync($function, array $arguments = []) |
107
|
|
|
{ |
108
|
|
|
$unSerialize = function ($input) { |
109
|
|
|
if (is_string($input)) { |
110
|
|
|
return unserialize($input); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return $input; |
114
|
|
|
}; |
115
|
|
|
|
116
|
|
|
return $this-> |
117
|
|
|
pool-> |
118
|
|
|
call(get_parent_class($this), $this->tableName, $function, $arguments)-> |
119
|
|
|
then($unSerialize, $unSerialize, $unSerialize) |
120
|
|
|
; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @param $class |
125
|
|
|
* @return bool |
126
|
|
|
*/ |
127
|
|
|
private function hasClassAnnotation($class) |
128
|
|
|
{ |
129
|
|
|
return is_a($this->annotationReader->getClassAnnotation($this->reflectionClass, $class), $class); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @param $method |
134
|
|
|
* @param $class |
135
|
|
|
* @return bool |
136
|
|
|
*/ |
137
|
|
|
private function hasMethodAnnotation($method, $class) |
138
|
|
|
{ |
139
|
|
|
$methodReflection = $this->reflectionClass->getMethod($method); |
140
|
|
|
|
141
|
|
|
return is_a($this->annotationReader->getMethodAnnotation($methodReflection, $class), $class); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @param $method |
146
|
|
|
* @return bool |
147
|
|
|
*/ |
148
|
|
|
private function hasNoMethodAnnotation($method) |
149
|
|
|
{ |
150
|
|
|
$methodReflection = $this->reflectionClass->getMethod($method); |
151
|
|
|
|
152
|
|
|
return ( |
153
|
|
|
$this->annotationReader->getMethodAnnotation($methodReflection, Async::class) === null && |
154
|
|
|
$this->annotationReader->getMethodAnnotation($methodReflection, Sync::class) === null |
155
|
|
|
); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @param $function |
160
|
|
|
* @return bool |
161
|
|
|
*/ |
162
|
|
|
private function returnsQuery($function) |
163
|
|
|
{ |
164
|
|
|
$docBlockContents = $this->reflectionClass->getMethod($function)->getDocComment(); |
165
|
|
|
if (!is_string($docBlockContents)) { |
166
|
|
|
return false; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
$docBlock = $this->getDocBlock($docBlockContents); |
170
|
|
|
foreach ($docBlock->getTags() as $tag) { |
171
|
|
|
if ($tag->getName() === 'return' && ltrim($tag->getType(), '\\') == Query::class) { |
|
|
|
|
172
|
|
|
return true; |
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
return false; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @param $docBlockContents |
181
|
|
|
* @return DocBlock |
182
|
|
|
*/ |
183
|
|
|
private function getDocBlock($docBlockContents) |
184
|
|
|
{ |
185
|
|
|
if (class_exists('phpDocumentor\Reflection\DocBlockFactory')) { |
186
|
|
|
return DocBlockFactory::createInstance()->create($docBlockContents); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
return new DocBlock($docBlockContents); |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.