Skip to content

Commit b90ebf3

Browse files
committed
dockblock plugin implemented
1 parent e3daf27 commit b90ebf3

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed

src/Plugins/DocBlock.php

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
3+
namespace Tarantool\Mapper\Plugins;
4+
5+
use Exception;
6+
7+
use phpDocumentor\Reflection\DocBlockFactory;
8+
use ReflectionClass;
9+
use ReflectionProperty;
10+
11+
use Tarantool\Mapper\Entity;
12+
use Tarantool\Mapper\Plugin;
13+
use Tarantool\Mapper\Repository;
14+
15+
class DocBlock extends UserClasses
16+
{
17+
private $entities = [];
18+
private $repositories = [];
19+
20+
public function register($class)
21+
{
22+
$isEntity = is_subclass_of($class, Entity::class);
23+
$isRepository = is_subclass_of($class, Repository::class);
24+
25+
if(!$isEntity && !$isRepository) {
26+
throw new Exception("Invalid registration");
27+
}
28+
29+
if($isEntity) {
30+
if($class == Entity::class) {
31+
throw new Exception("Invalid entity registration");
32+
}
33+
$this->entities[] = $class;
34+
}
35+
36+
if($isRepository) {
37+
if($class == Repository::class) {
38+
throw new Exception("Invalid repository registration");
39+
}
40+
$this->repositories[] = $class;
41+
}
42+
43+
$reflection = new ReflectionClass($class);
44+
$space = $this->toUnderscore($reflection->getShortName());
45+
if($this->mapper->getSchema()->hasSpace($space)) {
46+
if($isEntity) {
47+
$this->mapEntity($name, $class);
48+
} else {
49+
$this->mapRepository($name, $class);
50+
}
51+
}
52+
}
53+
54+
public function migrate()
55+
{
56+
$factory = DocBlockFactory::createInstance();
57+
58+
$schema = $this->mapper->getSchema();
59+
60+
foreach($this->entities as $entity) {
61+
62+
$class = new ReflectionClass($entity);
63+
$spaceName = $this->toUnderscore($class->getShortName());
64+
65+
$space = $schema->hasSpace($spaceName) ? $schema->getSpace($spaceName) : $schema->createSpace($spaceName);
66+
$this->mapEntity($spaceName, $entity);
67+
68+
foreach($class->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
69+
70+
$description = $factory->create($property->getDocComment());
71+
$tags = $description->getTags('var');
72+
73+
if(!count($tags)) {
74+
throw new Exception("No var tag for ".$entity.'::'.$property->getName());
75+
}
76+
77+
if(count($tags) > 1) {
78+
throw new Exception("Invalid var tag for ".$entity.'::'.$property->getName());
79+
}
80+
81+
$property = $this->toUnderscore($property->getName());
82+
$type = $this->getTarantoolType($tags[0]->getType());
83+
84+
if(!$space->hasProperty($property)) {
85+
$space->addProperty($property, $type);
86+
}
87+
}
88+
}
89+
90+
foreach($this->repositories as $repository) {
91+
92+
$class = new ReflectionClass($repository);
93+
$spaceName = $this->toUnderscore($class->getShortName());
94+
95+
if(!$schema->hasSpace($spaceName)) {
96+
throw new Exception("Repository with no entity definition");
97+
}
98+
99+
$this->mapRepository($spaceName, $repository);
100+
101+
$space = $schema->getSpace($spaceName);
102+
$properties = $class->getDefaultProperties();
103+
if(array_key_exists('indexes', $properties)) {
104+
foreach($properties['indexes'] as $index) {
105+
$space->addIndex($index);
106+
}
107+
}
108+
}
109+
110+
foreach($schema->getSpaces() as $space) {
111+
112+
if(!count($space->getIndexes())) {
113+
if(!$space->hasProperty('id')) {
114+
throw new Exception("No primary index on ". $space->getName());
115+
}
116+
$space->addIndex(['id']);
117+
}
118+
}
119+
}
120+
121+
private $underscores = [];
122+
123+
private function toUnderscore($input)
124+
{
125+
if(!array_key_exists($input, $this->underscores)) {
126+
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
127+
$ret = $matches[0];
128+
foreach ($ret as &$match) {
129+
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
130+
}
131+
$this->underscores[$input] = implode('_', $ret);
132+
}
133+
return $this->underscores[$input];
134+
}
135+
136+
private $tarantoolTypes = [];
137+
138+
private function getTarantoolType(string $type)
139+
{
140+
if(array_key_exists($type, $this->tarantoolTypes)) {
141+
return $this->tarantoolTypes[$type];
142+
}
143+
144+
switch($type) {
145+
case 'int':
146+
return $this->tarantoolTypes[$type] = 'unsigned';
147+
148+
default:
149+
return $this->tarantoolTypes[$type] = 'str';
150+
}
151+
}
152+
}

tests/DockBlockTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
use Tarantool\Mapper\Plugins\DocBlock;
4+
use Tarantool\Mapper\Plugins\Sequence;
5+
use Tarantool\Mapper\Entity;
6+
use Tarantool\Mapper\Repository;
7+
8+
class DocBlockTest extends TestCase
9+
{
10+
public function test()
11+
{
12+
$mapper = $this->createMapper();
13+
$this->clean($mapper);
14+
15+
$orm = $mapper->addPlugin(Sequence::class);
16+
$orm = $mapper->addPlugin(DocBlock::class);
17+
18+
$orm->register('Entities\\Post');
19+
$orm->register('Entities\\Person');
20+
$orm->register('Repositories\\Post');
21+
22+
$orm->migrate();
23+
24+
$nekufa = $mapper->create('person', [
25+
'name' => 'Dmitry.Krokhin'
26+
]);
27+
28+
$post = $mapper->create('post', [
29+
'slug' => 'test',
30+
'title' => 'Testing',
31+
'author' => $nekufa,
32+
]);
33+
34+
$this->assertInstanceOf('Entities\\Person', $nekufa);
35+
$this->assertInstanceOf('Repositories\\Post', $mapper->getSchema()->getSpace('post')->getRepository());
36+
}
37+
}
38+

tests/Entities/Person.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Entities;
4+
5+
use Tarantool\Mapper\Entity;
6+
7+
class Person extends Entity
8+
{
9+
/**
10+
* @var integer
11+
*/
12+
public $id;
13+
14+
/**
15+
* @var string
16+
*/
17+
public $name;
18+
}
19+

tests/Entities/Post.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Entities;
4+
5+
use Tarantool\Mapper\Entity;
6+
7+
class Post extends Entity
8+
{
9+
/**
10+
* @var integer
11+
*/
12+
public $id;
13+
14+
/**
15+
* @var string
16+
*/
17+
public $slug;
18+
19+
/**
20+
* @var string
21+
*/
22+
public $title;
23+
24+
/**
25+
* @var Person
26+
*/
27+
public $author;
28+
}

tests/Repositories/Post.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Repositories;
4+
5+
use Tarantool\Mapper\Repository;
6+
7+
class Post extends Repository
8+
{
9+
public $indexes = [
10+
['id'],
11+
['slug']
12+
];
13+
}

0 commit comments

Comments
 (0)