Algo-Web /
POData-Laravel
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | /** |
||
| 5 | * Created by PhpStorm. |
||
| 6 | * User: alex |
||
| 7 | * Date: 14/02/20 |
||
| 8 | * Time: 10:54 PM. |
||
| 9 | */ |
||
| 10 | namespace AlgoWeb\PODataLaravel\Query; |
||
| 11 | |||
| 12 | use Illuminate\Database\Eloquent\Builder; |
||
| 13 | use Illuminate\Database\Eloquent\Collection; |
||
| 14 | use Illuminate\Database\Eloquent\Model; |
||
| 15 | use Illuminate\Database\Eloquent\Relations\Relation; |
||
| 16 | use Illuminate\Support\Facades\App; |
||
| 17 | use POData\Common\InvalidOperationException; |
||
| 18 | use POData\Common\ODataException; |
||
| 19 | use POData\Providers\Metadata\ResourceSet; |
||
| 20 | use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo; |
||
| 21 | use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor; |
||
| 22 | use Symfony\Component\Process\Exception\InvalidArgumentException; |
||
| 23 | |||
| 24 | trait LaravelReadQueryUtilityTrait |
||
| 25 | { |
||
| 26 | /** @var string|null */ |
||
| 27 | protected $name; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * @param SkipTokenInfo $skipToken |
||
| 31 | * @param Model|Builder $sourceEntityInstance |
||
| 32 | * @throws InvalidOperationException |
||
| 33 | * @return mixed |
||
| 34 | */ |
||
| 35 | protected function processSkipToken(SkipTokenInfo $skipToken, $sourceEntityInstance) |
||
| 36 | { |
||
| 37 | $parameters = []; |
||
| 38 | $processed = []; |
||
| 39 | $segments = $skipToken->getOrderByInfo()->getOrderByPathSegments(); |
||
| 40 | $values = $skipToken->getOrderByKeysInToken(); |
||
| 41 | $numValues = count($values); |
||
| 42 | if ($numValues != count($segments)) { |
||
| 43 | $msg = 'Expected ' . count($segments) . ', got ' . $numValues; |
||
| 44 | throw new InvalidOperationException($msg); |
||
| 45 | } |
||
| 46 | |||
| 47 | for ($i = 0; $i < $numValues; $i++) { |
||
| 48 | $relation = $segments[$i]->isAscending() ? '>' : '<'; |
||
| 49 | $name = $segments[$i]->getSubPathSegments()[0]->getName(); |
||
| 50 | $baseVal = $values[$i][0]; |
||
| 51 | /** @var string $rawValue */ |
||
| 52 | $rawValue = is_string($baseVal) ? $baseVal : $baseVal->/** @scrutinizer ignore-call */toString(); |
||
| 53 | $parameters[$name] = [ |
||
| 54 | 'direction' => $relation, |
||
| 55 | 'value' => trim(/** @scrutinizer ignore-type */$rawValue, '\'') |
||
| 56 | ]; |
||
| 57 | } |
||
| 58 | |||
| 59 | foreach ($parameters as $name => $line) { |
||
| 60 | $processed[$name] = ['direction' => $line['direction'], 'value' => $line['value']]; |
||
| 61 | $sourceEntityInstance = $sourceEntityInstance |
||
| 62 | ->orWhere( |
||
| 63 | function (Builder $query) use ($processed) { |
||
| 64 | foreach ($processed as $key => $proc) { |
||
| 65 | $query->where($key, $proc['direction'], $proc['value']); |
||
| 66 | } |
||
| 67 | } |
||
| 68 | ); |
||
| 69 | // now we've handled the later-in-order segment for this key, drop it back to equality in prep |
||
| 70 | // for next key - same-in-order for processed keys and later-in-order for next |
||
| 71 | $processed[$name]['direction'] = '='; |
||
| 72 | } |
||
| 73 | return $sourceEntityInstance; |
||
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @param ResourceSet $resourceSet |
||
| 78 | * @throws \ReflectionException |
||
| 79 | * @return mixed |
||
| 80 | */ |
||
| 81 | protected function getSourceEntityInstance(ResourceSet $resourceSet) |
||
| 82 | { |
||
| 83 | $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name; |
||
| 84 | return App::make($entityClassName); |
||
| 85 | } |
||
| 86 | |||
| 87 | /** |
||
| 88 | * @param Model|Relation|null $source |
||
| 89 | * @param ResourceSet $resourceSet |
||
| 90 | * @throws \ReflectionException |
||
| 91 | * @return Model|Relation|mixed|null |
||
| 92 | */ |
||
| 93 | protected function checkSourceInstance($source, ResourceSet $resourceSet) |
||
| 94 | { |
||
| 95 | if (!(null == $source || $source instanceof Model || $source instanceof Relation)) { |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 96 | $msg = 'Source entity instance must be null, a model, or a relation.'; |
||
| 97 | throw new InvalidArgumentException($msg); |
||
| 98 | } |
||
| 99 | |||
| 100 | if (null == $source) { |
||
| 101 | $source = $this->getSourceEntityInstance(/* @scrutinizer ignore-type */$resourceSet); |
||
| 102 | } |
||
| 103 | |||
| 104 | return $source; |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * @param Model|Relation|Builder $sourceEntityInstance |
||
| 109 | * @param KeyDescriptor|null $keyDescriptor |
||
| 110 | * @throws InvalidOperationException |
||
| 111 | */ |
||
| 112 | protected function processKeyDescriptor(&$sourceEntityInstance, KeyDescriptor $keyDescriptor = null): void |
||
| 113 | { |
||
| 114 | if ($keyDescriptor) { |
||
| 115 | $table = ($sourceEntityInstance instanceof Model) ? $sourceEntityInstance->getTable() . '.' : ''; |
||
| 116 | foreach ($keyDescriptor->getValidatedNamedValues() as $key => $value) { |
||
| 117 | $trimValue = trim($value[0], '\''); |
||
| 118 | $sourceEntityInstance = $sourceEntityInstance->where($table . $key, $trimValue); |
||
| 119 | } |
||
| 120 | } |
||
| 121 | } |
||
| 122 | |||
| 123 | /** |
||
| 124 | * @param string[] $eagerLoad |
||
| 125 | * @throws InvalidOperationException |
||
| 126 | * @return string[] |
||
| 127 | */ |
||
| 128 | protected function processEagerLoadList(array $eagerLoad = []): array |
||
| 129 | { |
||
| 130 | $rawLoad = []; |
||
| 131 | foreach ($eagerLoad as $line) { |
||
| 132 | if (!is_string($line)) { |
||
| 133 | throw new InvalidOperationException('Eager-load elements must be non-empty strings'); |
||
| 134 | } |
||
| 135 | $lineParts = explode('/', $line); |
||
| 136 | $numberOfParts = count($lineParts); |
||
| 137 | for ($i = 0; $i < $numberOfParts; $i++) { |
||
| 138 | $lineParts[$i] = $this->getLaravelRelationName($lineParts[$i]); |
||
| 139 | } |
||
| 140 | $remixLine = implode('.', $lineParts); |
||
| 141 | $rawLoad[] = $remixLine; |
||
| 142 | } |
||
| 143 | return $rawLoad; |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * @param string $odataProperty |
||
| 148 | * @return string |
||
| 149 | */ |
||
| 150 | protected function getLaravelRelationName(string $odataProperty) |
||
| 151 | { |
||
| 152 | $laravelProperty = $odataProperty; |
||
| 153 | $pos = strrpos($laravelProperty, '_'); |
||
| 154 | if ($pos !== false) { |
||
| 155 | $laravelProperty = substr($laravelProperty, 0, $pos); |
||
| 156 | } |
||
| 157 | return $laravelProperty; |
||
| 158 | } |
||
| 159 | } |
||
| 160 |