Stinger-Soft /
EntitySearchBundle
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /* |
||
| 4 | * This file is part of the Stinger Enity Search package. |
||
| 5 | * |
||
| 6 | * (c) Oliver Kotte <[email protected]> |
||
| 7 | * (c) Florian Meyer <[email protected]> |
||
| 8 | * |
||
| 9 | * For the full copyright and license information, please view the LICENSE |
||
| 10 | * file that was distributed with this source code. |
||
| 11 | */ |
||
| 12 | namespace StingerSoft\EntitySearchBundle\Services\Mapping; |
||
| 13 | |||
| 14 | use StingerSoft\EntitySearchBundle\Model\SearchableEntity; |
||
| 15 | use Doctrine\Common\Persistence\ObjectManager; |
||
| 16 | use StingerSoft\EntitySearchBundle\Model\Document; |
||
| 17 | use Symfony\Component\PropertyAccess\PropertyAccess; |
||
| 18 | use StingerSoft\EntitySearchBundle\Services\SearchService; |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Handles the creation of documents out of entities |
||
| 22 | */ |
||
| 23 | class EntityToDocumentMapper implements EntityToDocumentMapperInterface { |
||
| 24 | |||
| 25 | /** |
||
| 26 | * |
||
| 27 | * @var SearchService |
||
| 28 | */ |
||
| 29 | protected $searchService; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * |
||
| 33 | * @var string[string] |
||
| 34 | */ |
||
| 35 | protected $mapping = array(); |
||
| 36 | |||
| 37 | /** |
||
| 38 | * |
||
| 39 | * @var string[string] |
||
| 40 | */ |
||
| 41 | protected $cachedMapping = array(); |
||
| 42 | |||
| 43 | /** |
||
| 44 | * Constructor |
||
| 45 | * |
||
| 46 | * @param SearchService $searchService |
||
| 47 | */ |
||
| 48 | public function __construct(SearchService $searchService, array $mapping = array()) { |
||
| 49 | $this->searchService = $searchService; |
||
| 50 | foreach($mapping as $key => $config) { |
||
| 51 | if(!isset($config['mappings'])) { |
||
| 52 | throw new \InvalidArgumentException($key . ' has no mapping defined!'); |
||
| 53 | } |
||
| 54 | if(!isset($config['persistence'])) { |
||
| 55 | throw new \InvalidArgumentException($key . ' has no persistence defined!'); |
||
| 56 | } |
||
| 57 | if(!isset($config['persistence']['model'])) { |
||
| 58 | throw new \InvalidArgumentException($key . ' has no model defined!'); |
||
| 59 | } |
||
| 60 | $map = array(); |
||
| 61 | foreach($config['mappings'] as $fieldKey => $fieldConfig) { |
||
| 62 | $map[$fieldKey] = isset($fieldConfig['propertyPath']) && $fieldConfig['propertyPath'] ? $fieldConfig['propertyPath'] : $fieldKey; |
||
| 63 | } |
||
| 64 | |||
| 65 | $this->mapping[$config['persistence']['model']] = $map; |
||
| 66 | } |
||
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * |
||
| 71 | * {@inheritDoc} |
||
| 72 | * |
||
| 73 | * @see \StingerSoft\EntitySearchBundle\Services\Mapping\EntityToDocumentMapperInterface::isIndexable() |
||
| 74 | */ |
||
| 75 | public function isIndexable($object) { |
||
| 76 | if($object instanceof SearchableEntity) { |
||
| 77 | return true; |
||
| 78 | } |
||
| 79 | if(count($this->getMapping($object)) > 0) { |
||
| 80 | return true; |
||
| 81 | } |
||
| 82 | return false; |
||
| 83 | } |
||
| 84 | |||
| 85 | |||
| 86 | /** |
||
| 87 | * {@inheritDoc} |
||
| 88 | * @see \StingerSoft\EntitySearchBundle\Services\Mapping\EntityToDocumentMapperInterface::createDocument() |
||
| 89 | */ |
||
| 90 | public function createDocument(ObjectManager $manager, $object) { |
||
| 91 | if(!$this->isIndexable($object)) |
||
| 92 | return false; |
||
| 93 | $document = $this->getSearchService($manager)->createEmptyDocumentFromEntity($object); |
||
| 94 | $index = $this->fillDocument($document, $object); |
||
| 95 | if($index == false) |
||
| 96 | return false; |
||
| 97 | |||
| 98 | return $document; |
||
|
0 ignored issues
–
show
|
|||
| 99 | } |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Fills the given document based on the object |
||
| 103 | * |
||
| 104 | * @param Document $document |
||
| 105 | * @param object $object |
||
| 106 | * @return boolean |
||
| 107 | */ |
||
| 108 | protected function fillDocument(Document &$document, $object) { |
||
| 109 | if($object instanceof SearchableEntity) { |
||
| 110 | return $object->indexEntity($document); |
||
| 111 | } |
||
| 112 | $mapping = $this->getMapping($object); |
||
| 113 | $accessor = PropertyAccess::createPropertyAccessor(); |
||
| 114 | foreach($mapping as $fieldName => $propertyPath) { |
||
| 115 | $document->addField($fieldName, $accessor->getValue($object, $propertyPath)); |
||
| 116 | } |
||
| 117 | return true; |
||
| 118 | } |
||
| 119 | |||
| 120 | /** |
||
| 121 | * Fetches the mapping for the given object including the mapping of superclasses |
||
| 122 | * |
||
| 123 | * @param object $object |
||
| 124 | * @return \StingerSoft\EntitySearchBundle\Services\string[string] |
||
| 125 | */ |
||
| 126 | protected function getMapping($object) { |
||
| 127 | $clazz = get_class($object); |
||
| 128 | if(isset($this->cachedMapping[$clazz])) { |
||
| 129 | return $this->cachedMapping[$clazz]; |
||
| 130 | } |
||
| 131 | $ref = new \ReflectionClass($clazz); |
||
| 132 | |||
| 133 | $mapping = array(); |
||
| 134 | |||
| 135 | foreach($this->mapping as $className => $config) { |
||
| 136 | if($clazz == $className || $ref->isSubclassOf($className)) { |
||
| 137 | $mapping = array_merge($mapping, $config); |
||
| 138 | } |
||
| 139 | } |
||
| 140 | |||
| 141 | $this->cachedMapping[$clazz] = $mapping; |
||
| 142 | |||
| 143 | return $mapping; |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Returns the search service |
||
| 148 | * |
||
| 149 | * @return SearchService |
||
| 150 | */ |
||
| 151 | protected function getSearchService(ObjectManager $manager) { |
||
| 152 | $this->searchService->setObjectManager($manager); |
||
| 153 | return $this->searchService; |
||
| 154 | } |
||
| 155 | } |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.