Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Annotation/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
*/
final class Document
{
/**
* @var bool
*/
public $create;

/**
* @var string
*/
Expand All @@ -33,4 +38,12 @@ final class Document
* @var array
*/
public $ttl;

/**
* Constructor.
*/
public function __construct()
{
$this->create = true;
}
}
46 changes: 46 additions & 0 deletions Annotation/Inherit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the ONGR package.
*
* (c) NFQ Technologies UAB <info@nfq.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ONGR\ElasticsearchBundle\Annotation;

/**
* Annotation used inherit properties during the parsing process.
*
* @Annotation
* @Target("CLASS")
*/
final class Inherit
{
/**
* @var array
*/
public $value;

/**
* Constructor.
*
* @param array $values
*
* @throws \InvalidArgumentException
*/
public function __constructor(array $values)
{
if (is_string($values['value'])) {
$this->value = [$values['value']];
} elseif (is_array($values['value'])) {
$this->value = $values['value'];
} else {
throw new \InvalidArgumentException(
'Annotation Inherit unexpected type given. Expected string or array, given ' . gettype($values['value'])
);
}
}
}
46 changes: 46 additions & 0 deletions Annotation/Skip.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the ONGR package.
*
* (c) NFQ Technologies UAB <info@nfq.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ONGR\ElasticsearchBundle\Annotation;

/**
* Annotation used to skip properties during the parsing process.
*
* @Annotation
* @Target("CLASS")
*/
final class Skip
{
/**
* @var array
*/
public $value;

/**
* Constructor.
*
* @param array $values
*
* @throws \InvalidArgumentException
*/
public function __constructor(array $values)
{
if (is_string($values['value'])) {
$this->value = [$values['value']];
} elseif (is_array($values['value'])) {
$this->value = $values['value'];
} else {
throw new \InvalidArgumentException(
'Annotation Inherit unexpected type given. Expected string or array, given ' . gettype($values['value'])
);
}
}
}
101 changes: 89 additions & 12 deletions Mapping/MetadataCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,20 +215,25 @@ private function getDocumentReflectionMapping(\ReflectionClass $reflectionClass)
{
/** @var Document $class */
$class = $this->reader->getClassAnnotation($reflectionClass, 'ONGR\ElasticsearchBundle\Annotation\Document');
if ($class !== null) {
if ($class !== null && $class->create) {
$type = $this->getDocumentType($reflectionClass, $class);
$parent = $class->parent === null ? $class->parent : $this->getDocumentParentType($class->parent);
$properties = $this->getProperties($reflectionClass);
$inherit = $this->getInheritedProperties($reflectionClass);

$setters = [];
$getters = [];
$properties = $this->getProperties(
$reflectionClass,
array_merge($inherit, $this->getSkippedProperties($reflectionClass))
);

foreach ($properties as $property => $params) {
$alias = $this->aliases[$reflectionClass->getName()][$property];
list($setters[$property], $getters[$property]) = $this
->getInfoAboutProperty($params, $alias, $reflectionClass);
if (!empty($inherit)) {
$properties = array_merge(
$properties,
$this->getProperties($reflectionClass->getParentClass(), $inherit, true)
);
}

list($setters, $getters) = $this->getSettersAndGetters($reflectionClass, $properties);

$class = [
$type => [
'properties' => $properties,
Expand All @@ -248,6 +253,70 @@ private function getDocumentReflectionMapping(\ReflectionClass $reflectionClass)
return $class;
}

/**
* Returns information about accessing properties from document.
*
* @param \ReflectionClass $reflectionClass Document reflection class.
* @param array $properties Document properties.
*
* @return array
*/
private function getSettersAndGetters(\ReflectionClass $reflectionClass, array $properties)
{
$setters = [];
$getters = [];

foreach ($properties as $property => $params) {
if (array_key_exists($property, $this->aliases[$reflectionClass->getName()])) {
list($setters[$property], $getters[$property]) = $this
->getInfoAboutProperty(
$params,
$this->aliases[$reflectionClass->getName()][$property],
$reflectionClass
);
} elseif ($reflectionClass->getParentClass() !== false) {
list($parentSetters, $parentGetters) = $this
->getSettersAndGetters($reflectionClass->getParentClass(), [$property => $params]);

if ($parentSetters !== []) {
$setters = array_merge($setters, $parentSetters);
}

if ($parentGetters !== []) {
$getters = array_merge($getters, $parentGetters);
}
}
}

return [$setters, $getters];
}

/**
* @param \ReflectionClass $reflectionClass
*
* @return array
*/
private function getSkippedProperties(\ReflectionClass $reflectionClass)
{
/** @var Skip $class */
$class = $this->reader->getClassAnnotation($reflectionClass, 'ONGR\ElasticsearchBundle\Annotation\Skip');

return $class === null ? [] : $class->value;
}

/**
* @param \ReflectionClass $reflectionClass
*
* @return array
*/
private function getInheritedProperties(\ReflectionClass $reflectionClass)
{
/** @var Inherit $class */
$class = $this->reader->getClassAnnotation($reflectionClass, 'ONGR\ElasticsearchBundle\Annotation\Inherit');

return $class === null ? [] : $class->value;
}

/**
* Returns document type.
*
Expand Down Expand Up @@ -304,6 +373,7 @@ private function getInfoAboutProperty($params, $alias, $reflectionClass)
* @param \ReflectionClass $reflectionClass
*
* @return array
*
* @throws \LogicException
*/
private function checkPropertyAccess($property, $methodPrefix, $reflectionClass)
Expand Down Expand Up @@ -405,19 +475,23 @@ private function getDocumentParentType($namespace)
/**
* Returns properties of reflection class.
*
* @param \ReflectionClass $reflectionClass
* @param \ReflectionClass $reflectionClass Class to read properties from.
* @param array $properties Properties to skip.
* @param array $flag If false exludes properties, true only includes properties.
*
* @return array
* @throws \RuntimeException
*/
private function getProperties(\ReflectionClass $reflectionClass)
private function getProperties(\ReflectionClass $reflectionClass, $properties = [], $flag = false)
{
$mapping = [];
/** @var \ReflectionProperty $property */
foreach ($reflectionClass->getProperties() as $property) {
$type = $this->getPropertyAnnotationData($property);

if (empty($type)) {
if ((in_array($property->getName(), $properties) && !$flag)
|| (!in_array($property->getName(), $properties) && $flag)
|| empty($type)
) {
continue;
}

Expand Down Expand Up @@ -483,6 +557,8 @@ private function registerAnnotations()
'Object',
'Nested',
'MultiField',
'Inherit',
'Skip',
'Suggester/CompletionSuggesterProperty',
'Suggester/ContextSuggesterProperty',
'Suggester/Context/CategoryContext',
Expand Down Expand Up @@ -519,6 +595,7 @@ private function getNamespace($namespace)
* @param string $name
*
* @return string
*
* @throws \LogicException
*/
private function getBundle($name)
Expand Down
3 changes: 2 additions & 1 deletion Resources/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Main things you should know while working with this bundle.

More specific features and usages that you might need.

- (Coming soon)
- [Document inheritance](inheritance.md)
- [Autocomplete, suggesters](suggesters/usage.md)
77 changes: 77 additions & 0 deletions Resources/doc/inheritance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
### Document Inheritance

By default annotations inherit all properties that have been defined in parent document. We have implemented Skip and Inherit annotations to make inheritance to be less of a headache. F.e.

```php

/**
* Document class Item.
*
* @ES\Document(create=false)
*/
class Item implements DocumentInterface
{
use DocumentTrait;

/**
* @var string
*
* @ES\Property(name="name", type="string")
*/
public $name;

/**
* @var float
*
* @ES\Property(type="float", name="price")
*/
public $price;

/**
* @var \DateTime
*
* @ES\Property(name="created_at", type="date")
*/
public $createdAt;
}

/**
* Product document for testing.
*
* @ES\Document(type="product")
* @ES\Skip({"name"})
* @ES\Inherit({"price"})
*/
class Product extends Item implements DocumentInterface
{
use DocumentTrait;

/**
* @var string
*
* @ES\Property(type="string", name="title", fields={@ES\MultiField(name="raw", type="string")})
*/
public $title;

/**
* @var string
*
* @ES\Property(type="string", name="description")
*/
public $description;

/**
* @var int
*
* @ES\Property(type="integer", name="price")
*/
public $price;
}

```

In this example Product document inherits all properties from Item. Let's pretend that we dont want property `$name` in Product document. So we just add `@ES\Skip("name")` or if we want multiple skip's `@ES\Skip({"price", "description"})`.

> Annotations above class are not inherited.

Next imagine that we want to extend this product document later but it should have price as integer (not float like Item), but this Type should have it as float and we dont want to rewrite price as integer everywhere. Thats where `@ES\Inherit` kicks in. **It inherits properties from parent documents if it has been defined in current document**. So product document in this example will have price as float.
3 changes: 0 additions & 3 deletions Resources/doc/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,3 @@ $documents = $repository->findBy(['title' => 'Acme']);
````

To perform a more complex queries there is a Search DSL API. Read more about it in [Search DSL](search.md) chapter.

### Autocomplete
To use autocomplete follow [suggesters](suggesters/usage.md) section.
3 changes: 3 additions & 0 deletions Tests/Unit/Mapping/MetadataCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ protected function getProductMapping()
],
],
],
'created_at' => [
'type' => 'date',
]
];
}

Expand Down
Loading