Changeset 57417

Show
Ignore:
Timestamp:
04/07/08 16:38:19 (3 months ago)
Author:
ischommer
Message:

FEATURE Added getSearchQuery(), getObjectQuery(), getObjectsQuery(), getObjectRelationQuery() to RestfulServer?
FEATURE Added $totalSize to DataFormatter? to add useful output for pagination via "limit" and "offset" parameters
API CHANGE Removed RestfulServer?->search()
API CHANGE Changed output format for convertDataObjectSet() in XMLDataFormatter and JSONDataFormatter

Location:
modules/sapphire/branches/roa/api
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • modules/sapphire/branches/roa/api/DataFormatter.php

    r56976 r57417  
    6262         */ 
    6363        protected $outputContentType = null; 
     64         
     65        /** 
     66         * Used to set totalSize properties on the output 
     67         * of {@link convertDataObjectSet()}, shows the 
     68         * total number of records without the "limit" and "offset" 
     69         * GET parameters. Useful to implement pagination. 
     70         *  
     71         * @var int 
     72         */ 
     73        protected $totalSize; 
    6474         
    6575        /** 
     
    184194         
    185195        /** 
     196         * @param int $size 
     197         */ 
     198        public function setTotalSize($size) { 
     199                $this->totalSize = (int)$size; 
     200        } 
     201         
     202        /** 
     203         * @return int 
     204         */ 
     205        public function getTotalSize() { 
     206                return $this->totalSize; 
     207        } 
     208         
     209        /** 
    186210         * Returns all fields on the object which should be shown 
    187211         * in the output. Can be customised through {@link self::setCustomFields()}. 
  • modules/sapphire/branches/roa/api/JSONDataFormatter.php

    r55564 r57417  
    9191                        if($item->canView()) $jsonParts[] = $this->convertDataObject($item); 
    9292                } 
    93                 return "[\n" . implode(",\n", $jsonParts) . "\n]"; 
     93                $json = "{\n"; 
     94                $json .= 'totalSize: '; 
     95                $json .= (is_numeric($this->totalSize)) ? $this->totalSize : 'null'; 
     96                $json .= ",\n"; 
     97                $json .= "items: [\n" . implode(",\n", $jsonParts) . "\n]\n"; 
     98                $json .= "}\n"; 
     99 
     100                return $json; 
    94101        } 
    95102         
  • modules/sapphire/branches/roa/api/RestfulServer.php

    r57048 r57417  
    141141         * @return String The serialized representation of the requested object(s) - usually XML or JSON. 
    142142         */ 
    143         protected function getHandler($className, $id, $relation) { 
     143        protected function getHandler($className, $id, $relationName) { 
    144144                $sort = array( 
    145145                        'sort' => $this->request->getVar('sort'), 
     
    151151                ); 
    152152                 
     153                $params = $this->request->getVars(); 
     154                 
    153155                $responseFormatter = $this->getResponseDataFormatter(); 
    154156                if(!$responseFormatter) return $this->unsupportedMediaType(); 
    155157                 
     158                // $obj can be either a DataObject or a DataObjectSet, 
     159                // depending on the request 
    156160                if($id) { 
    157                         $obj = DataObject::get_by_id($className, $id); 
     161                        // Format: /api/v1/<MyClass>/<ID> 
     162                        $query = $this->getObjectQuery($className, $id, $params); 
     163                        $obj = singleton($className)->buildDataObjectSet($query->execute()); 
    158164                        if(!$obj) return $this->notFound(); 
     165                        $obj = $obj->First(); 
    159166                        if(!$obj->canView()) return $this->permissionFailure(); 
    160167 
    161                         if($relation) { 
    162                                 if($relationClass = $obj->many_many($relation)) { 
    163                                         $query = $obj->getManyManyComponentsQuery($relation); 
    164                                 } elseif($relationClass = $obj->has_many($relation)) { 
    165                                         $query = $obj->getComponentsQuery($relation); 
    166                                 } elseif($relationClass = $obj->has_one($relation)) { 
    167                                         $query = null; 
    168                                 } elseif($obj->hasMethod("{$relation}Query")) { 
    169                                         // @todo HACK Switch to ComponentSet->getQuery() once we implement it (and lazy loading) 
    170                                         $query = $obj->{"{$relation}Query"}(null, $sort, null, $limit); 
    171                                         $relationClass = $obj->{"{$relation}Class"}(); 
    172                                 } else { 
    173                                         return $this->notFound(); 
    174                                 } 
    175  
    176                                 // get all results 
    177                                 $obj = $this->search($relationClass, $this->request->getVars(), $sort, $limit, $query); 
    178                                 if(!$obj) $obj = new DataObjectSet(); 
     168                        // Format: /api/v1/<MyClass>/<ID>/<Relation> 
     169                        if($relationName) { 
     170                                $query = $this->getObjectRelationQuery($obj, $params, $sort, $limit, $relationName); 
     171                                if($query === false) return $this->notFound(); 
     172                                $obj = singleton($className)->buildDataObjectSet($query->execute()); 
    179173                        }  
    180174                         
    181175                } else { 
    182                         $obj = $this->search($className, $this->request->getVars(), $sort, $limit); 
     176                        // Format: /api/v1/<MyClass> 
     177                        $query = $this->getObjectsQuery($className, $params, $sort, $limit); 
     178                        $obj = singleton($className)->buildDataObjectSet($query->execute()); 
     179 
    183180                        // show empty serialized result when no records are present 
    184181                        if(!$obj) $obj = new DataObjectSet(); 
     
    186183                 
    187184                $this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType()); 
    188                  
    189                 if($obj instanceof DataObjectSet) return $responseFormatter->convertDataObjectSet($obj); 
    190                 else return $responseFormatter->convertDataObject($obj); 
     185 
     186                if($obj instanceof DataObjectSet) { 
     187                        $responseFormatter->setTotalSize($query->unlimitedRowCount()); 
     188                        return $responseFormatter->convertDataObjectSet($obj); 
     189                } else { 
     190                        return $responseFormatter->convertDataObject($obj); 
     191                } 
    191192        } 
    192193         
     
    203204         * @return DataObjectSet 
    204205         */ 
    205         protected function search($className, $params = null, $sort = null, $limit = null, $existingQuery = null) { 
     206        protected function getSearchQuery($className, $params = null, $sort = null, $limit = null, $existingQuery = null) { 
    206207                if(singleton($className)->hasMethod('getRestfulSearchContext')) { 
    207208                        $searchContext = singleton($className)->{'getRestfulSearchContext'}(); 
     
    210211                } 
    211212                $query = $searchContext->getQuery($params, $sort, $limit, $existingQuery); 
    212  
    213                 return singleton($className)->buildDataObjectSet($query->execute()); 
    214         } 
    215  
     213                 
     214                return $query; 
     215        } 
     216         
    216217        /** 
    217218         * Returns a dataformatter instance based on the request 
     
    356357        } 
    357358         
     359        /** 
     360         * Gets a single DataObject by ID, 
     361         * through a request like /api/v1/<MyClass>/<MyID> 
     362         *  
     363         * @param string $className 
     364         * @param int $id 
     365         * @param array $params 
     366         * @return SQLQuery 
     367         */ 
     368        protected function getObjectQuery($className, $id, $params) { 
     369                return singleton($className)->buildSQL( 
     370                        "ID = {$id}" 
     371                ); 
     372        } 
     373         
     374        /** 
     375         * @param DataObject $obj 
     376         * @param array $params 
     377         * @param int|array $sort 
     378         * @param int|array $limit 
     379         * @return SQLQuery 
     380         */ 
     381        protected function getObjectsQuery($className, $params, $sort, $limit) { 
     382                return $this->getSearchQuery($className, $params, $sort, $limit); 
     383        } 
     384         
     385         
     386        /** 
     387         * @param DataObject $obj 
     388         * @param array $params 
     389         * @param int|array $sort 
     390         * @param int|array $limit 
     391         * @param string $relationName 
     392         * @return SQLQuery|boolean 
     393         */ 
     394        protected function getObjectRelationQuery($obj, $params, $sort, $limit, $relationName) { 
     395                if($relationClass = $obj->many_many($relationName)) { 
     396                        $query = $obj->getManyManyComponentsQuery($relationName); 
     397                } elseif($relationClass = $obj->has_many($relationName)) { 
     398                        $query = $obj->getComponentsQuery($relationName); 
     399                } elseif($relationClass = $obj->has_one($relationName)) { 
     400                        $query = null; 
     401                } elseif($obj->hasMethod("{$relation}Query")) { 
     402                        // @todo HACK Switch to ComponentSet->getQuery() once we implement it (and lazy loading) 
     403                        $query = $obj->{"{$relation}Query"}(null, $sort, null, $limit); 
     404                        $relationClass = $obj->{"{$relation}Class"}(); 
     405                } else { 
     406                        return false; 
     407                } 
     408 
     409                // get all results 
     410                return $this->getSearchQuery($relationClass, $params, $sort, $limit); 
     411        } 
     412         
    358413        protected function permissionFailure() { 
    359414                // return a 401 
  • modules/sapphire/branches/roa/api/XMLDataFormatter.php

    r55565 r57417  
    9797                $className = $set->class; 
    9898         
    99                 $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<$className>\n"; 
     99                $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 
     100                $xml .= (is_numeric($this->totalSize)) ? "<$className totalSize=\"{$this->totalSize}\">\n" : "<$className>\n"; 
    100101                foreach($set as $item) { 
    101102                        if($item->canView()) $xml .= $this->convertDataObjectWithoutHeader($item);