Пример #1
0
 public function validateValues()
 {
     if (is_array($this->value) && !Condition::isValidMultipleModelsOperator($this->operator)) {
         throw new InvalidOperatorException();
     } else {
         if (!is_array($this->value) && !Condition::isValidSingleModelOperator($this->operator)) {
             throw new InvalidOperatorException();
         }
     }
 }
Пример #2
0
 public function get(Request $request)
 {
     $modelClassName = $this->modelClassName;
     $query = $modelClassName::getModelQuery();
     $limit = null;
     $page = null;
     $sort = null;
     // variables to build our links later on
     $jsonapi = new JsonApiRootNode();
     // We start by adding the link to this request
     $baseUrl = $request->getSchemeAndHttpHost() . $request->getPathInfo();
     // this might not work with a different port than 80, check later
     // Get requests can either be a list of models, or an individual model, so we must check the slug
     if (empty($this->slug)) {
         // when we don't have a slug, we are expected to always return an array response,
         // even when the result is a single object
         $jsonapi->asArray(true);
         // when the slug is empty, we must check for extra variables
         if ($request->query->has('limit') && is_numeric($request->query->get('limit'))) {
             $limit = $request->query->get('limit');
         }
         // Additional check for the page variable, we potentially need to adjust the query start
         if ($request->query->has('page') && is_numeric($request->query->get('page'))) {
             $page = $request->query->get('page');
             if (!empty($limit)) {
                 $start = ($page - 1) * $limit;
                 $query->setRange($start, $limit);
             } else {
                 $start = ($page - 1) * $this->maxLimit;
                 $query->setRange($start, $this->maxLimit);
             }
         } else {
             // no page, we can just set a limit
             if (empty($limit)) {
                 // no limit, lets set the default one
                 $query->setLimit($this->maxLimit);
             } else {
                 $query->setLimit($limit);
             }
         }
         // Lets get the pretty to regular field mapping for use in either sort or filter
         $prettyToFieldsMap = $modelClassName::getPrettyFieldsToFieldsMapping();
         // Lets also check for an order
         if ($request->query->has('sort')) {
             // sort params are split by ',' so lets evaluate them individually
             $sort = $request->query->get('sort');
             $sortQueryFields = explode(',', $sort);
             foreach ($sortQueryFields as $sortQueryField) {
                 // the json-api spec tells us, that all fields are sorted ascending, unless the field is prepended by a '-'
                 // http://jsonapi.org/format/#fetching-sorting
                 $direction = !empty($sortQueryField) && $sortQueryField[0] === '-' ? 'DESC' : 'ASC';
                 $prettyField = ltrim($sortQueryField, '-');
                 // lets remove the '-' from the start of the field if it exists
                 $prettyFieldParts = explode('.', $prettyField);
                 // if the pretty field exists, lets add it to the sort order
                 if (array_key_exists($prettyFieldParts[0], $prettyToFieldsMap)) {
                     $field = $prettyToFieldsMap[$prettyFieldParts[0]];
                     if (sizeof($prettyFieldParts) > 1) {
                         $typePrettyToFieldsMap = $modelClassName::getTypePrettyFieldToFieldsMapping();
                         // meaning we have a extra column present
                         $fieldDefinition = $modelClassName::getFieldDefinition($field);
                         $fieldType = $fieldDefinition->getType();
                         if (array_key_exists($fieldType, $typePrettyToFieldsMap) && array_key_exists($prettyFieldParts[1], $typePrettyToFieldsMap[$fieldType])) {
                             $column = $typePrettyToFieldsMap[$fieldType][$prettyFieldParts[1]];
                             $query->addSortOrder($field . '.' . $column, $direction);
                         }
                     } else {
                         $query->addSortOrder($field, $direction);
                     }
                 }
             }
         }
         // Before we fetch the collection, lets check for filters
         if ($request->query->has('filter')) {
             $filter = $request->query->get('filter');
             if (is_array($filter)) {
                 foreach (array_keys($filter) as $prettyField) {
                     // lets start by making sure the field exists
                     // we explode, because we have a potential field with a column (like address.city) as opposed to just a field (like name)
                     $prettyFieldParts = explode('.', $prettyField);
                     if (array_key_exists($prettyFieldParts[0], $prettyToFieldsMap)) {
                         $field = $prettyToFieldsMap[$prettyFieldParts[0]];
                         $operator = null;
                         $value = null;
                         $filterValue = $filter[$prettyField];
                         // the filter value can either be the specific value, or an array with extra attributes
                         if (is_array($filterValue)) {
                             // we found an array, meaning we must check for 'operator' as well
                             $operator = array_key_exists('operator', $filterValue) && Condition::isValidSingleModelOperator($filterValue['operator']) ? $filterValue['operator'] : null;
                             $value = array_key_exists('value', $filterValue) ? $filterValue['value'] : null;
                         } else {
                             // no array, so it will just be the value
                             $operator = '=';
                             $value = $filterValue;
                         }
                         if (!empty($operator) && !empty($value) && !empty($field)) {
                             if (sizeof($prettyFieldParts) > 1) {
                                 // this means we have a field with a column (like address.city)
                                 $typePrettyToFieldsMap = $modelClassName::getTypePrettyFieldToFieldsMapping();
                                 // meaning we have a extra column present
                                 $fieldDefinition = $modelClassName::getFieldDefinition($field);
                                 $fieldType = $fieldDefinition->getType();
                                 if (array_key_exists($fieldType, $typePrettyToFieldsMap) && array_key_exists($prettyFieldParts[1], $typePrettyToFieldsMap[$fieldType])) {
                                     $column = $typePrettyToFieldsMap[$fieldType][$prettyFieldParts[1]];
                                     $condition = new Condition($field . '.' . $column, $operator, $value);
                                     $query->addCondition($condition);
                                 }
                             } else {
                                 // just a field, no column (like name)
                                 $condition = new Condition($field, $operator, $value);
                                 $query->addCondition($condition);
                             }
                         }
                     }
                 }
             }
         }
         // Here we build the links of the request
         $this->addSingleLink($jsonapi, 'self', $baseUrl, $limit, $page, $sort);
         // here we add the self link
         $result = $query->fetchCollection();
         if (!$result->isEmpty) {
             // we must include pagination links when there are more than the maximum amount of results
             if ($result->size === $this->maxLimit) {
                 $previousPage = empty($page) ? 0 : $page - 1;
                 // the first link is easy, it is the first page
                 $this->addSingleLink($jsonapi, 'first', $baseUrl, 0, 1, $sort);
                 // the previous link, checks if !empty, so pages with value 0 will not be displayed
                 if (!empty($previousPage)) {
                     $this->addSingleLink($jsonapi, 'previous', $baseUrl, 0, $previousPage, $sort);
                 }
                 // next we check the total count, to see if we can display the last & next link
                 $totalCount = $query->fetchTotalCount();
                 if (!empty($totalCount)) {
                     $lastPage = ceil($totalCount / $this->maxLimit);
                     $currentPage = empty($page) ? 1 : $page;
                     $this->addSingleLink($jsonapi, 'last', $baseUrl, 0, $lastPage, $sort);
                     // let's include some meta data
                     $jsonapi->addMeta('count', (int) $result->size);
                     $jsonapi->addMeta('total-count', (int) $totalCount);
                     $jsonapi->addMeta('page-count', (int) $lastPage);
                     $jsonapi->addMeta('page-size', (int) $this->maxLimit);
                     $jsonapi->addMeta('page-current', (int) $currentPage);
                     if (!empty($previousPage)) {
                         $jsonapi->addMeta('page-prev', (int) $previousPage);
                     }
                     // and finally, we also check if the next page isn't larger than the last page
                     $nextPage = empty($page) ? 2 : $page + 1;
                     if ($nextPage <= $lastPage) {
                         $this->addSingleLink($jsonapi, 'next', $baseUrl, 0, $nextPage, $sort);
                         $jsonapi->addMeta('page-next', (int) $nextPage);
                     }
                     $jsonapi->addMeta('result-row-first', (int) (($currentPage - 1) * $this->maxLimit) + 1);
                     $jsonapi->addMeta('result-row-last', (int) $result->size < $this->maxLimit ? ($currentPage - 1) * $this->maxLimit + $result->size : $currentPage * $this->maxLimit);
                 }
             } else {
                 if (!empty($limit)) {
                     // we must also include pagination links when we have a limit defined
                     $previousPage = empty($page) ? 0 : $page - 1;
                     // the first link is easy, it is the first page
                     $this->addSingleLink($jsonapi, 'first', $baseUrl, $limit, 1, $sort);
                     // the previous link, checks if !empty, so pages with value 0 will not be displayed
                     if (!empty($previousPage)) {
                         $this->addSingleLink($jsonapi, 'prev', $baseUrl, $limit, $previousPage, $sort);
                     }
                     // next we check the total count, to see if we can display the last & next link
                     $totalCount = $query->fetchTotalCount();
                     if (!empty($totalCount)) {
                         $lastPage = ceil($totalCount / $limit);
                         $currentPage = empty($page) ? 1 : $page;
                         $this->addSingleLink($jsonapi, 'last', $baseUrl, $limit, $lastPage, $sort);
                         // let's include some meta data
                         $jsonapi->addMeta('count', (int) $result->size);
                         $jsonapi->addMeta('total-count', (int) $totalCount);
                         $jsonapi->addMeta('page-count', (int) $lastPage);
                         $jsonapi->addMeta('page-size', (int) $limit);
                         $jsonapi->addMeta('page-current', (int) $currentPage);
                         if (!empty($previousPage)) {
                             $jsonapi->addMeta('page-prev', (int) $previousPage);
                         }
                         // and finally, we also check if the next page isn't larger than the last page
                         $nextPage = empty($page) ? 2 : $page + 1;
                         if ($nextPage <= $lastPage) {
                             $this->addSingleLink($jsonapi, 'next', $baseUrl, $limit, $nextPage, $sort);
                             $jsonapi->addMeta('page-next', (int) $nextPage);
                         }
                         $jsonapi->addMeta('result-row-first', (int) (($currentPage - 1) * $limit) + 1);
                         $jsonapi->addMeta('result-row-last', (int) $result->size < $limit ? ($currentPage - 1) * $limit + $result->size : $currentPage * $limit);
                     }
                 } else {
                     $jsonapi->addMeta('count', (int) $result->size);
                     $jsonapi->addMeta('total-count', (int) $result->size);
                     $jsonapi->addMeta('page-count', (int) 1);
                     $jsonapi->addMeta('page-size', (int) $this->maxLimit);
                     $jsonapi->addMeta('page-current', (int) 1);
                     $jsonapi->addMeta('result-row-first', (int) 1);
                     $jsonapi->addMeta('result-row-last', (int) $result->size);
                 }
             }
             $node = $result->getJsonApiNode();
             $jsonapi->setData($node);
             if ($request->query->has('include')) {
                 // includes are comma seperated
                 $includes = explode(',', $request->query->get('include'));
                 if (!empty($includes)) {
                     $this->checkForIncludes($result, $jsonapi, $includes);
                 }
             }
         }
     } else {
         $query->addCondition(new Condition($modelClassName::$idField, '=', $this->slug));
         $result = $query->fetchSingleModel();
         $this->addSingleLink($jsonapi, 'self', $baseUrl);
         if (!empty($result)) {
             $jsonapi->addNode($result->getJsonApiNode());
             // let's check for includes as well
             if ($request->query->has('include')) {
                 // includes are comma seperated
                 $includes = explode(',', $request->query->get('include'));
                 if (!empty($includes)) {
                     $this->checkForIncludes($result, $jsonapi, $includes);
                 }
             }
         } else {
             // we musn't do anything, json api provides an empty node out of the box
         }
     }
     return new Response(json_encode($jsonapi->serialize()), 200, array());
 }