<?php namespace ApiQL; use Doctrine\DBAL\Query\QueryBuilder; use ApiQL\Language\AbstractLanguage; use ApiQL\Language\ApiQueryBuilder; use ApiQL\Language\LanguageFactory; /** * Class ApiQL * * @package ApiQL */ class ApiQL extends AbstractLanguage { public function __construct(array $expression, QueryBuilder $builder, array $specs = []) { $this->expression = $expression; self::$builder = new ApiQueryBuilder($builder); self::$specs = $specs; } /** * Execute specification root expression */ public function execute() { $this->executeFields(); $this->executeOffset(); $this->executeLimit(); $this->executeOrder(); $this->executeWhere(); } /** * Execute fields part of expression */ private function executeFields() { $isProjection = false; if (array_key_exists('fields', $this->expression)) { $isProjection = true; $fieldsName = 'fields'; } elseif (array_key_exists('select', $this->expression)) { $isProjection = true; $fieldsName = 'select'; } if ($isProjection) { $fields = !is_array($this->expression[$fieldsName]) ? explode(',', $this->expression[$fieldsName]) : $this->expression[$fieldsName]; if (!empty($fields)) { foreach ($fields as $field) { self::$builder->addSelect($field); } } else { self::$builder->addSelect('*'); } unset($this->expression[$fieldsName]); } else { self::$builder->addSelect('*'); } } /** * Execute offset part of expression */ private function executeOffset() { if (array_key_exists('offset', $this->expression)) { self::$builder->setFirstResult($this->expression['offset']); unset($this->expression['offset']); } } /** * Execute limit part of expression */ private function executeLimit() { if (array_key_exists('limit', $this->expression)) { self::$builder->setMaxResults($this->expression['limit']); unset($this->expression['limit']); } } /** * Execute fields part of expression */ private function executeOrder() { if (array_key_exists('order', $this->expression)) { $fields = !is_array($this->expression['order']) ? explode(',', $this->expression['order']) : $this->expression['order']; if (!empty($fields)) { foreach ($fields as $field) { $pair = explode(':', $field); $fieldName = $pair[0]; $orderType = (count($pair) == 2) ? $pair[1] : null; self::$builder->addOrderBy($fieldName, $orderType); } } unset($this->expression['order']); } } /** * Execute where part of expression */ private function executeWhere() { if (!empty($this->expression)) { if (array_key_exists('where', $this->expression)) { $expression = $this->expression['where']; $operator = array_key_first($expression); $data_ = $expression[$operator]; if (self::isLogicOperator($operator)) { $interpreters = array_map(function ($item) { return LanguageFactory::build($item); }, $data_); self::$builder->andWhere($this->method($operator, ...$interpreters)); } elseif (self::isRelationOperator($operator) || self::isSpecification($operator)) { $interpreter = LanguageFactory::build($expression); self::$builder->andWhere($interpreter->execute()); } } else { if (array_key_exists(self::SPEC, $this->expression)) { $specName = $this->expression[self::SPEC]; unset($this->expression[self::SPEC]); $this->expression = array_merge([self::SPEC => $specName], $this->expression); $interpreter = LanguageFactory::build($this->expression); self::$builder->andWhere($interpreter->execute()); } else { $logic = self::getLogicOperator($this->expression); $rel = self::getRelationOperator($this->expression); if (array_key_exists(self::RELATION, $this->expression)) { unset($this->expression[self::RELATION]); } if (array_key_exists(self::LOGIC, $this->expression)) { unset($this->expression[self::LOGIC]); } $expression = [$logic => []]; foreach ($this->expression as $key => $value) { $expression[$logic][] = [$rel => [$key => $value]]; } $interpreters = array_map(function ($item) { return LanguageFactory::build($item); }, $expression[$logic]); self::$builder->andWhere($this->method($logic, ...$interpreters)); } } } } }