Overview
  • Package
  • Class
  • Tree
  • Todo

Packages

  • AddonValue
    • Interfaces
  • ApiV2Controllers
  • Category
    • Collections
    • Entities
    • Factories
    • Interfaces
    • Providers
    • Repositories
    • Storages
  • Customer
    • Address
    • Country
    • CountryZone
    • Interfaces
    • Validation
    • ValueObjects
  • Email
    • Collections
    • Entities
    • Exceptions
    • Interfaces
    • Repository
    • ValueObjects
  • Http
    • Collections
    • Exceptions
    • Factories
    • Interfaces
    • ValueObjects
  • Loaders
    • CrossCuttingLoader
    • GXCoreLoader
    • Interfaces
  • None
  • Order
    • Collections
    • Entities
    • Factories
    • Interfaces
    • Repositories
    • Storages
    • ValueObjects
  • Product
    • Collections
    • Entities
    • Factories
    • Interfaces
    • Providers
    • Repositories
    • Storages
  • ProductModule
    • Collections
    • Deleter
    • Entities
    • Factories
    • Interface
    • Interfaces
    • Reader
    • Repositories
    • Writer
  • Shared
    • Exceptions
    • FileSystem
    • Interfaces
    • Storage
    • Types
  • Statistics
    • Interfaces
  • UserConfiguration
    • Interfaces
    • Repository

Classes

  • AbstractAddonValueServiceFactory
  • AbstractAddonValueStorage
  • AbstractApiV2Controller
  • AbstractCategoryServiceFactory
  • AbstractCollection
  • AbstractCustomerFactory
  • AbstractCustomerServiceFactory
  • AbstractFileStorage
  • AbstractHttpContextFactory
  • AbstractHttpViewControllerRegistryFactory
  • AbstractImagesApiV2Controller
  • AbstractOrderServiceFactory
  • AbstractProductAttributeServiceFactory
  • AbstractProductServiceFactory
  • AddonValueService
  • AddonValueServiceFactory
  • AddonValueStorageFactory
  • AddressBlock
  • AddressBookService
  • AddressClass
  • AddressesApiV2Controller
  • AddressFormatProvider
  • AdminHttpViewController
  • AdminPageHttpControllerResponse
  • Asset
  • AssetCollection
  • AttachmentCollection
  • AttachmentName
  • AttachmentPath
  • AttachmentsApiV2Controller
  • AttachmentsHandler
  • BoolType
  • CategoriesApiV2Controller
  • Category
  • CategoryAddonValueStorage
  • CategoryFactory
  • CategoryIconsApiV2Controller
  • CategoryImagesApiV2Controller
  • CategoryListItem
  • CategoryListItemCollection
  • CategoryListProvider
  • CategoryListProviderFactory
  • CategoryObjectService
  • CategoryReadService
  • CategoryRepository
  • CategoryRepositoryDeleter
  • CategoryRepositoryReader
  • CategoryRepositoryWriter
  • CategoryServiceFactory
  • CategorySettings
  • CategorySettingsRepository
  • CategorySettingsRepositoryReader
  • CategorySettingsRepositoryWriter
  • CategoryWriteService
  • ContactCollection
  • ContactName
  • ContactType
  • CountriesApiV2Controller
  • CountryService
  • CrossCuttingLoader
  • CurrencyCode
  • Customer
  • CustomerAccountInputValidator
  • CustomerAddress
  • CustomerAddressDeleter
  • CustomerAddressInputValidator
  • CustomerAddressReader
  • CustomerAddressRepository
  • CustomerAddressWriter
  • CustomerB2BStatus
  • CustomerCallNumber
  • CustomerCity
  • CustomerCompany
  • CustomerCountry
  • CustomerCountryIso2
  • CustomerCountryIso3
  • CustomerCountryName
  • CustomerCountryReader
  • CustomerCountryRepository
  • CustomerCountryZone
  • CustomerCountryZoneIsoCode
  • CustomerCountryZoneName
  • CustomerCountryZoneReader
  • CustomerCountryZoneRepository
  • CustomerDateOfBirth
  • CustomerDeleter
  • CustomerEmail
  • CustomerFactory
  • CustomerFirstname
  • CustomerGender
  • CustomerInputValidator
  • CustomerInputValidatorSettings
  • CustomerLastname
  • CustomerNumber
  • CustomerPassword
  • CustomerPostcode
  • CustomerReader
  • CustomerReadService
  • CustomerRegistrationInputValidatorService
  • CustomerRepository
  • CustomersApiV2Controller
  • CustomerService
  • CustomerServiceFactory
  • CustomerServiceSettings
  • CustomerStatusInformation
  • CustomerStatusProvider
  • CustomerStreet
  • CustomerSuburb
  • CustomerVatNumber
  • CustomerWriter
  • CustomerWriteService
  • DecimalType
  • DefaultApiV2Controller
  • EditableCollection
  • EditableKeyValueCollection
  • Email
  • EmailAddress
  • EmailAttachment
  • EmailCollection
  • EmailContact
  • EmailContent
  • EmailDeleter
  • EmailFactory
  • EmailReader
  • EmailRepository
  • EmailsApiV2Controller
  • EmailService
  • EmailStringType
  • EmailSubject
  • EmailWriter
  • EmptyCurrencyCode
  • EmptyDateTime
  • EmptyLanguageCode
  • EmptyOrderItemDownloadInformation
  • EmptyProductImage
  • EnvCategoryServiceSettings
  • EnvironmentHttpContextFactory
  • EnvironmentHttpViewControllerRegistryFactory
  • EnvProductImageFileStorageSettings
  • ExistingDirectory
  • ExistingFile
  • FilenameStringType
  • GXCoreLoader
  • GXCoreLoaderSettings
  • GXEngineOrder
  • GXEngineProduct
  • HttpApiV2Controller
  • HttpContext
  • HttpContextReader
  • HttpControllerResponse
  • HttpDispatcher
  • HttpResponseProcessor
  • HttpService
  • HttpServiceFactory
  • HttpViewController
  • HttpViewControllerFactory
  • HttpViewControllerRegistry
  • IdCollection
  • IdType
  • ImageFileStorage
  • IntType
  • JsonHttpControllerResponse
  • KeyValueCollection
  • LanguageCode
  • LegacyProductImageProcessing
  • MailerAdapter
  • NonEmptyStringType
  • OrderAddonValueStorage
  • OrderFactory
  • OrderItem
  • OrderItemAddonValueStorage
  • OrderItemAttribute
  • OrderItemAttributeCollection
  • OrderItemAttributeFactory
  • OrderItemAttributeRepository
  • OrderItemAttributeRepositoryDeleter
  • OrderItemAttributeRepositoryFactory
  • OrderItemAttributeRepositoryReader
  • OrderItemAttributeRepositoryWriter
  • OrderItemCollection
  • OrderItemDownloadInformation
  • OrderItemFactory
  • OrderItemProperty
  • OrderItemPropertyFactory
  • OrderItemPropertyRepository
  • OrderItemPropertyRepositoryDeleter
  • OrderItemPropertyRepositoryReader
  • OrderItemPropertyRepositoryWriter
  • OrderItemRepository
  • OrderItemRepositoryDeleter
  • OrderItemRepositoryReader
  • OrderItemRepositoryWriter
  • OrderListGenerator
  • OrderListItem
  • OrderListItemCollection
  • OrderObjectService
  • OrderPaymentType
  • OrderReadService
  • OrderRepository
  • OrderRepositoryDeleter
  • OrderRepositoryReader
  • OrderRepositoryWriter
  • OrdersApiV2Controller
  • OrderServiceFactory
  • OrderServiceSettings
  • OrderShippingType
  • OrdersHistoryApiV2Controller
  • OrdersItemsApiV2Controller
  • OrdersItemsAttributesApiV2Controller
  • OrderStatusHistoryListItem
  • OrderStatusHistoryListItemCollection
  • OrderStatusHistoryStorage
  • OrdersTotalsApiV2Controller
  • OrderTotal
  • OrderTotalCollection
  • OrderTotalFactory
  • OrderTotalRepository
  • OrderTotalRepositoryDeleter
  • OrderTotalRepositoryReader
  • OrderTotalRepositoryWriter
  • OrderWriteService
  • ProductAddonValueStorage
  • ProductAttribute
  • ProductAttributeCollection
  • ProductAttributeFactory
  • ProductAttributeObjectService
  • ProductAttributeRepository
  • ProductAttributeRepositoryDeleter
  • ProductAttributeRepositoryReader
  • ProductAttributeRepositoryWriter
  • ProductAttributeService
  • ProductAttributeServiceFactory
  • ProductCategoryLinker
  • ProductFactory
  • ProductImage
  • ProductImageCollection
  • ProductImageContainer
  • ProductImageContainerRepository
  • ProductImageFileStorage
  • ProductImagesApiV2Controller
  • ProductListItem
  • ProductListItemCollection
  • ProductListProvider
  • ProductListProviderFactory
  • ProductObjectService
  • ProductPermissionSetter
  • ProductReadService
  • ProductRepository
  • ProductRepositoryDeleter
  • ProductRepositoryReader
  • ProductRepositoryWriter
  • ProductsApiV2Controller
  • ProductServiceFactory
  • ProductSettings
  • ProductSettingsRepository
  • ProductSettingsRepositoryReader
  • ProductSettingsRepositoryWriter
  • ProductsLinksApiV2Controller
  • ProductWriteService
  • RedirectHttpControllerResponse
  • StaticCrossCuttingLoader
  • StaticGXCoreLoader
  • StatisticsService
  • StoredCategory
  • StoredOrderItem
  • StoredOrderItemAttribute
  • StoredOrderItemAttributeCollection
  • StoredOrderItemCollection
  • StoredOrderItemProperty
  • StoredOrderTotal
  • StoredOrderTotalCollection
  • StoredProduct
  • StoredProductAttribute
  • StoredProductAttributeCollection
  • StringCollection
  • StringType
  • UserConfigurationReader
  • UserConfigurationService
  • UserConfigurationWriter
  • VatNumberValidator
  • WritableDirectory
  • WritableFile
  • YetAnotherLanguageProvider
  • ZonesApiV2Controller

Interfaces

  • AddonValueContainerInterface
  • AddonValueServiceInterface
  • AddonValueStorageFactoryInterface
  • AddressBlockInterface
  • AddressBookServiceInterface
  • AddressClassInterface
  • AddressFormatProviderInterface
  • AssetCollectionInterface
  • AssetInterface
  • AttachmentCollectionInterface
  • AttachmentNameInterface
  • AttachmentPathInterface
  • AttachmentsHandlerInterface
  • CategoryFactoryInterface
  • CategoryInterface
  • CategoryListProviderFactoryInterface
  • CategoryListProviderInterface
  • CategoryObjectServiceInterface
  • CategoryReadServiceInterface
  • CategoryRepositoryDeleterInterface
  • CategoryRepositoryInterface
  • CategoryRepositoryReaderInterface
  • CategoryRepositoryWriterInterface
  • CategoryServiceSettingsInterface
  • CategorySettingsInterface
  • CategorySettingsRepositoryInterface
  • CategorySettingsRepositoryReaderInterface
  • CategorySettingsRepositoryWriterInterface
  • CategoryWriteServiceInterface
  • ContactCollectionInterface
  • ContactNameInterface
  • ContactTypeInterface
  • ContentViewInterface
  • CountryServiceInterface
  • CrossCuttingLoaderInterface
  • CrossCuttingObjectInterface
  • CustomerAccountInputValidatorInterface
  • CustomerAddressDeleterInterface
  • CustomerAddressInputValidatorInterface
  • CustomerAddressInterface
  • CustomerAddressReaderInterface
  • CustomerAddressRepositoryInterface
  • CustomerAddressWriterInterface
  • CustomerB2BStatusInterface
  • CustomerCallNumberInterface
  • CustomerCityInterface
  • CustomerCompanyInterface
  • CustomerCountryInterface
  • CustomerCountryIso2Interface
  • CustomerCountryIso3Interface
  • CustomerCountryNameInterface
  • CustomerCountryReaderInterface
  • CustomerCountryRepositoryInterface
  • CustomerCountryZoneInterface
  • CustomerCountryZoneIsoCodeInterface
  • CustomerCountryZoneNameInterface
  • CustomerCountryZoneReaderInterface
  • CustomerCountryZoneRepositoryInterface
  • CustomerDeleterInterface
  • CustomerEmailInterface
  • CustomerFirstnameInterface
  • CustomerGenderInterface
  • CustomerInputValidatorInterface
  • CustomerInputValidatorSettingsInterface
  • CustomerInterface
  • CustomerLastnameInterface
  • CustomerNumberInterface
  • CustomerPasswordInterface
  • CustomerPostcodeInterface
  • CustomerReaderInterface
  • CustomerReadServiceInterface
  • CustomerRegistrationInputValidatorServiceInterface
  • CustomerRepositoryInterface
  • CustomerServiceInterface
  • CustomerServiceSettingsInterface
  • CustomerStatusProviderInterface
  • CustomerStreetInterface
  • CustomerSuburbInterface
  • CustomerVatNumberInterface
  • CustomerWriterInterface
  • CustomerWriteServiceInterface
  • EmailAddressInterface
  • EmailAttachmentInterface
  • EmailCollectionInterface
  • EmailContactInterface
  • EmailContentInterface
  • EmailDeleterInterface
  • EmailFactoryInterface
  • EmailInterface
  • EmailReaderInterface
  • EmailRepositoryInterface
  • EmailServiceInterface
  • EmailSubjectInterface
  • EmailWriterInterface
  • GXCoreLoaderInterface
  • GXCoreLoaderSettingsInterface
  • HttpContextInterface
  • HttpContextReaderInterface
  • HttpControllerResponseInterface
  • HttpDispatcherInterface
  • HttpResponseProcessorInterface
  • HttpServiceFactoryInterface
  • HttpServiceInterface
  • HttpViewControllerFactoryInterface
  • HttpViewControllerInterface
  • HttpViewControllerRegistryInterface
  • IdInterface
  • LanguageProviderInterface
  • MailerAdapterInterface
  • OrderFactoryInterface
  • OrderInterface
  • OrderItemAttributeFactoryInterface
  • OrderItemAttributeInterface
  • OrderItemAttributeRepositoryDeleterInterface
  • OrderItemAttributeRepositoryFactoryInterface
  • OrderItemAttributeRepositoryInterface
  • OrderItemAttributeRepositoryReaderInterface
  • OrderItemAttributeRepositoryWriterInterface
  • OrderItemFactoryInterface
  • OrderItemInterface
  • OrderItemPropertyFactoryInterface
  • OrderItemPropertyRepositoryDeleterInterface
  • OrderItemPropertyRepositoryReaderInterface
  • OrderItemPropertyRepositoryWriterInterface
  • OrderItemRepositoryDeleterInterface
  • OrderItemRepositoryInterface
  • OrderItemRepositoryReaderInterface
  • OrderItemRepositoryWriterInterface
  • OrderListGeneratorInterface
  • OrderObjectServiceInterface
  • OrderPaymentTypeInterface
  • OrderReadServiceInterface
  • OrderRepositoryDeleterInterface
  • OrderRepositoryInterface
  • OrderRepositoryReaderInterface
  • OrderRepositoryWriterInterface
  • OrderServiceSettingsInterface
  • OrderShippingTypeInterface
  • OrderStatusHistoryReaderInterface
  • OrderStatusHistoryWriterInterface
  • OrderTotalFactoryInterface
  • OrderTotalInterface
  • OrderTotalRepositoryDeleterInterface
  • OrderTotalRepositoryInterface
  • OrderTotalRepositoryReaderInterface
  • OrderTotalRepositoryWriterInterface
  • OrderWriteServiceInterface
  • ProductAttributeFactoryInterface
  • ProductAttributeInterface
  • ProductAttributeObjectServiceInterface
  • ProductAttributeRepositoryDeleterInterface
  • ProductAttributeRepositoryInterface
  • ProductAttributeRepositoryReaderInterface
  • ProductAttributeRepositoryWriterInterface
  • ProductAttributeServiceInterface
  • ProductCategoryLinkerInterface
  • ProductFactoryInterface
  • ProductImageContainerInterface
  • ProductImageContainerRepositoryInterface
  • ProductImageInterface
  • ProductImagePathsSettingsInterface
  • ProductImageProcessingInterface
  • ProductInterface
  • ProductListProviderFactoryInterface
  • ProductListProviderInterface
  • ProductObjectServiceInterface
  • ProductPermissionSetterInterface
  • ProductReadServiceInterface
  • ProductRepositoryDeleterInterface
  • ProductRepositoryInterface
  • ProductRepositoryReaderInterface
  • ProductRepositoryWriterInterface
  • ProductSettingsInterface
  • ProductSettingsRepositoryInterface
  • ProductSettingsRepositoryReaderInterface
  • ProductSettingsRepositoryWriterInterface
  • ProductWriteServiceInterface
  • StatisticsServiceInterface
  • StoredCategoryInterface
  • StoredOrderItemAttributeInterface
  • StoredOrderItemInterface
  • StoredOrderTotalInterface
  • StoredProductAttributeInterface
  • StoredProductInterface
  • UserConfigurationReaderInterface
  • UserConfigurationServiceInterface
  • UserConfigurationWriterInterface
  • VatNumberValidatorInterface

Exceptions

  • AjaxException
  • AttachmentNotFoundException
  • FileNotFoundException
  • HttpApiV2Exception
  • MissingControllerNameException
  • UnknownEnvironmentException
  1 <?php
  2 /* --------------------------------------------------------------
  3    ApiController.php 2016-02-25
  4    Gambio GmbH
  5    http://www.gambio.de
  6    Copyright (c) 2016 Gambio GmbH
  7    Released under the GNU General Public License (Version 2)
  8    [http://www.gnu.org/licenses/gpl-2.0.html]
  9    --------------------------------------------------------------
 10 */
 11 
 12 MainFactory::load_class('AbstractApiV2Controller');
 13 
 14 /**
 15  * Class HttpApiV2Controller
 16  *
 17  * Contains common functionality for all the GX2 APIv2 controllers. You can use the $api instance in the
 18  * child-controllers in order to gain access to request and response information. The $uri variable is an
 19  * array that contains the requested resource path.
 20  *
 21  * You can use a protected "__initialize" method in your child controllers for performing common operations
 22  * without overriding the parent constructor method.
 23  *
 24  * This class contains some private methods that define the core operations of each controller and should
 25  * not be called from a child-controller (like validation, authorization, rate limiting). The only way to
 26  * disable the execution of these methods is to override the controller.
 27  *
 28  * @see      AbstractApiV2Controller
 29  *
 30  * @todo     Add _cacheResponse() helper function which will cache request data and it will provide the required
 31  *           headers.
 32  *
 33  * @category System
 34  * @package  ApiV2Controllers
 35  */
 36 class HttpApiV2Controller extends AbstractApiV2Controller
 37 {
 38     /**
 39      * Sort response array with the "sort" GET parameter.
 40      *
 41      * This method supports nested sort values, so by providing a "+address.street" value
 42      * to the "sort" GET parameter the records will be sort by street value in ascending
 43      * order. Method supports sorting up to 5 fields.
 44      *
 45      * Important #1:
 46      *    This method has some advantages and disadvantages over the classic database sort mechanism. First it
 47      *    does not need mapping between the API fields and the database fields. Second it does not depend on
 48      *    external system code to sort the response items, so if for example a domain-service does not support
 49      *    sorting the result can still be sorted before sent to the client. The disadvantages are that it will
 50      *    only support a predefined number of fields and this is a trade-off because the method should not use
 51      *    the "eval" function, which will introduce security risks. Furthermore it might be a bit slower than
 52      *    the database sorting.
 53      *
 54      * Important #2:
 55      *    This method is using PHP's array_multisort which by default will sort strings in a case sensitive
 56      *    manner. That means that strings starting with a capital letter will come before strings starting
 57      *    with a lowercase letter.
 58      *    http://php.net/manual/en/function.array-multisort.php
 59      *
 60      * Example:
 61      *   // will sort ascending by customer ID and descending by customer company
 62      *   api.php/v2/customers?sort=+id,-address.company
 63      *
 64      * @param array $response Passed by reference, contains an array of the multiple items
 65      *                        that will returned as a response to the client.
 66      */
 67     protected function _sortResponse(array &$response)
 68     {
 69         if($this->api->request->get('sort') === null)
 70         {
 71             return; // no sort parameter was provided
 72         }
 73 
 74         $params = explode(',', $this->api->request->get('sort'));
 75 
 76         for($i = 0; $i < 5; $i++)
 77         {
 78             $sort[$i] = array(
 79                 'array'     => array_fill(0, count($response), ''),
 80                 'direction' => SORT_ASC // default
 81             );
 82         }
 83 
 84         foreach($params as $paramIndex => &$param)
 85         {
 86             $fields = explode('.', substr($param, 1));
 87 
 88             foreach($response as $itemIndex => $item)
 89             {
 90                 $value = $item;
 91                 foreach($fields as $field)
 92                 {
 93                     $value = $value[$field];
 94                 }
 95 
 96                 $sort[$paramIndex]['direction']         = (substr($param, 0, 1) === '-') ? SORT_DESC : SORT_ASC;
 97                 $sort[$paramIndex]['array'][$itemIndex] = $value;
 98             }
 99         }
100 
101         // Multisort array (currently supports up to 5 sort fields).
102         array_multisort($sort[0]['array'], $sort[0]['direction'], $sort[1]['array'], $sort[1]['direction'],
103                         $sort[2]['array'], $sort[2]['direction'], $sort[3]['array'], $sort[3]['direction'],
104                         $sort[4]['array'], $sort[4]['direction'], $response);
105     }
106 
107 
108     /**
109      * Minimize response using the $fields parameter.
110      *
111      * APIv2 supports the GET "fields" parameter which enables the client to select the
112      * exact fields to be included in the response. It does not support nested fields,
113      * only first-level.
114      *
115      * You can provide both associative (single response item) or sequential (multiple response
116      * items) arrays and this method will adjust the links accordingly.
117      *
118      * @param array $response Passed by reference, it will be minified to the required fields.
119      */
120     protected function _minimizeResponse(array &$response)
121     {
122         if($this->api->request->get('fields') === null)
123         {
124             return; // no minification parameter was provided
125         }
126 
127         $fields = explode(',', $this->api->request->get('fields'));
128         $map    = array();
129         foreach($fields as $field)
130         {
131             $field       = array_shift(explode('.', $field)); // take only the first field
132             $map[$field] = array();
133         }
134 
135         // If $response array is associative then converted to sequential array.
136         $revertBackToAssociative = false;
137         if(key($response) !== 0 && !is_array($response[0]))
138         {
139             $response                = array($response);
140             $revertBackToAssociative = true;
141         }
142 
143         // Minimize all the items. 
144         foreach($response as &$item)
145         {
146             $item = array_intersect_key($item, $map);
147         }
148 
149         // Revert back to associative (if necessary).
150         if($revertBackToAssociative)
151         {
152             $response = $response[0];
153         }
154     }
155 
156 
157     /**
158      * Paginate response using the $page and $per_page GET parameters.
159      *
160      * One of the common functionalities of the APIv2 is the pagination and this can be
161      * easily achieved by this function which will update the response with the records
162      * that need to be returned. This method will automatically set the pagination headers
163      * in the response so that client apps can easily navigate through results.
164      *
165      * @param array $response Passed by reference, it will be paginated according to the provided parameters.
166      */
167     protected function _paginateResponse(array &$response)
168     {
169         if($this->api->request->get('page') === null)
170         {
171             return; // no pagination parameter was provided
172         }
173 
174         $limit          = ($this->api->request->get('per_page')
175                            !== null) ? $this->api->request->get('per_page') : self::DEFAULT_PAGE_ITEMS;
176         $offset         = $limit * ((int)$this->api->request->get('page') - 1);
177         $totalItemCount = count($response);
178         $this->_setPaginationHeader($this->api->request->get('page'), $limit, $totalItemCount);
179         $response = array_slice($response, $offset, $limit);
180     }
181 
182 
183     /**
184      * Include links to response resources.
185      *
186      * The APIv2 operates with simple resources that might be linked with other resources. This
187      * architecture promotes flexibility so that API consumers can have a simpler structure. This
188      * method will search for existing external resources and will add a link to the end of each
189      * resource.
190      *
191      * IMPORTANT: If for some reason you need to include custom links to your resources
192      * do not use this method. Include them inside your controller method manually.
193      *
194      * NOTICE #1: This method will only search at the first level of the resource. That means that
195      * nested ID values will not be taken into concern.
196      *
197      * NOTICE #2: You can provide both associative (single response item) or sequential (multiple response
198      * items) arrays and this method will adjust the links accordingly.
199      *
200      * @param array $response Passed by reference, new links will be appended into the end
201      *                        of each resource.
202      */
203     protected function _linkResponse(array &$response)
204     {
205         if($this->api->request->get('disable_links') !== null || count($response) === 0)
206         {
207             return; // client does not require links
208         }
209 
210         // Define the link mappings to the resources. 
211         $map = array(
212             'customerId' => 'customers',
213             'addressId'  => 'addresses',
214             'countryId'  => 'countries',
215             'zoneId'     => 'zones',
216             'ordersId'   => 'orders'
217         );
218 
219         // If $response array is associative then converted to sequential array. 
220         $revertBackToAssociative = false;
221         if(key($response) !== 0 && !is_array($response[0]))
222         {
223             $response                = array($response);
224             $revertBackToAssociative = true;
225         }
226 
227         // Parse the resource results and add the links.
228         foreach($response as &$item)
229         {
230             $links = array(); // will be appended to each resource
231 
232             foreach($map as $key => $resource)
233             {
234                 if(array_key_exists($key, $item) && $item[$key] !== null)
235                 {
236                     $links[str_replace('Id', '', $key)] = GM_HTTP_SERVER . $this->api->request->getRootUri() . '/v2/'
237                                                           . $resource . '/' . $item[$key];
238                 }
239             }
240 
241             $item['_links'] = $links;
242         }
243 
244         if($revertBackToAssociative)
245         {
246             $response = $response[0];
247         }
248     }
249 
250 
251     /**
252      * Write JSON encoded response data.
253      *
254      * Use this method to write a JSON encoded, pretty printed and unescaped response to
255      * the client consumer. It is very important that the API provides pretty printed responses
256      * because it is easier for users to debug and develop.
257      *
258      * IMPORTANT: PHP v5.3 does not support the JSON_PRETTY_PRINT and JSON_UNESCAPED_SLASHES so
259      * this method will check for their existance and then use them if possible.
260      *
261      * @param array $response     Contains the response data to be written.
262      * @param int   $p_statusCode (optional) Provide a custom status code for the response, default 200 - Success.
263      */
264     protected function _writeResponse(array $response, $p_statusCode = 200)
265     {
266         if($p_statusCode !== 200 && is_numeric($p_statusCode))
267         {
268             $this->api->response->setStatus((int)$p_statusCode);
269         }
270 
271         if(defined('JSON_PRETTY_PRINT') && defined('JSON_UNESCAPED_SLASHES'))
272         {
273             $responseJsonString = json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
274         }
275         else
276         {
277             $responseJsonString = json_encode($response); // PHP v5.3
278         }
279 
280         $this->api->response->write($responseJsonString);
281     }
282 
283 
284     /**
285      * Map the sub-resource to another controller.
286      *
287      * Some API resources contain many subresources which makes the creation of a single
288      * controller class complicated and hard to maintain. This method will forward the
289      * request to a another controller by checking the provided criteria.
290      *
291      * Example:
292      *
293      * $criteria = array(
294      *   'items'  => 'OrdersItemsAttributesApiV2Controller',
295      *   'totals' => 'OrdersTotalsApiV2Controller'
296      * );
297      *
298      * Notice: Each controller should map a direct subresource and not deeper ones. This way
299      * every API controller is responsible to map its direct subresources.
300      *
301      *
302      * @param array $criteria An array containing the mapping criteria.
303      *
304      * @return bool Returns whether the request was eventually mapped.
305      *
306      * @throws HttpApiV2Exception If the subresource is not supported by the API.
307      */
308     protected function _mapResponse(array $criteria)
309     {
310         $result = false;
311 
312         foreach($criteria as $subresource => $class)
313         {
314             for($i = count($this->uri) - 1; $i > 0; $i--)
315             {
316                 if($subresource === $this->uri[$i])
317                 {
318                     $controller = MainFactory::create($class, $this->api, $this->uri);
319                     $method     = strtolower($this->api->request->getMethod());
320                     $resource   = array($controller, $method);
321 
322                     if(!is_callable($resource))
323                     {
324                         throw new HttpApiV2Exception('The requested subresource is not supported by the API v2.', 400);
325                     }
326 
327                     call_user_func($resource);
328 
329                     $result = true;
330                     break 2; // Exit both loops.
331                 }
332             }
333         }
334 
335         return $result;
336     }
337 
338 
339     /**
340      * Perform a search on the response array.
341      *
342      * Normally the best way to filter the results is through the corresponding service but some times
343      * there is not specific method for searching the requested resource or subresource. When this is
344      * the case use this method to filter the results of the response before returning them back to the
345      * client.
346      *
347      * @param array  $response  Contains the response data to be written.
348      * @param string $p_keyword The keyword to be used for the search.
349      *
350      * @throws InvalidArgumentException If search keyword parameter is not a string.
351      */
352     protected function _searchResponse(array &$response, $p_keyword)
353     {
354         if(!is_string($p_keyword))
355         {
356             throw new InvalidArgumentException('Invalid argument provided (expected string got ' . gettype($p_keyword)
357                                                . '): ' . $p_keyword);
358         }
359 
360         if($p_keyword === '')
361         {
362             return; // do not perform the search
363         }
364 
365         $searchResults = array();
366 
367         foreach($response as $item)
368         {
369             if(!is_array($item))
370             {
371                 continue;
372             }
373 
374             foreach($item as $key => $value)
375             {
376                 if((is_string($value) || is_numeric($value)) && preg_match('/' . $p_keyword . '/i', $value) === 1)
377                 {
378                     $searchResults[] = $item;
379                     break;
380                 }
381             }
382         }
383 
384         $response = $searchResults;
385     }
386 
387 
388     /**
389      * Add location header to a specific response.
390      *
391      * Use this method whenever you want the "Location" header to point to an existing resource so that
392      * clients can use it to fetch that resource without having to generate the URL themselves.
393      *
394      * @param string $p_name
395      * @param int    $p_id
396      *
397      * @throws InvalidArgumentException If the arguments contain an invalid value.
398      */
399     protected function _locateResource($p_name, $p_id)
400     {
401         if(!is_string($p_name))
402         {
403             throw new InvalidArgumentException('Invalid argument provided (expected string got ' . gettype($p_name)
404                                                . '): ' . $p_name);
405         }
406 
407         if(!is_numeric($p_id))
408         {
409             throw new InvalidArgumentException('Invalid argument provided (expected int got ' . gettype($p_id) . '): '
410                                                . $p_id);
411         }
412 
413         $this->api->response->header('Location',
414                                      $this->api->request->getUrl() . $this->api->request->getRootUri() . '/v2/'
415                                      . $p_name . '/' . $p_id);
416     }
417 
418 
419     /**
420      * [PRIVATE] Set header pagination links.
421      *
422      * Useful for GET responses that return multiple items to the client. The client
423      * can use the links to navigate through the records without having to construct
424      * them on its own.
425      *
426      * @link http://www.w3.org/wiki/LinkHeader
427      *
428      * Not available to child-controllers (private method).
429      *
430      * @param int $p_currentPage    Current request page number.
431      * @param int $p_itemsPerPage   The number of items to be returned in each page.
432      * @param int $p_totalItemCount Total number of the resource items.
433      *
434      * @throws HttpApiV2Exception If one of the parameters are invalid.
435      */
436     private function _setPaginationHeader($p_currentPage, $p_itemsPerPage, $p_totalItemCount)
437     {
438         if($p_itemsPerPage <= 0)
439         {
440             throw new HttpApiV2Exception('Items per page number must not be below 1.', 400);
441         }
442 
443         $totalPages  = ceil($p_totalItemCount / $p_itemsPerPage);
444         $linksArray  = array();
445         $baseLinkUri = HTTP_SERVER . $this->api->request->getRootUri() . $this->api->request->getResourceUri();
446         $getParams   = $this->api->request->get();
447 
448         if($p_currentPage > 1)
449         {
450             $getParams['page']   = 1;
451             $linksArray['first'] = '<' . $baseLinkUri . '?' . http_build_query($getParams) . '>; rel="first"';
452 
453             $getParams['page']      = $p_currentPage - 1;
454             $linksArray['previous'] = '<' . $baseLinkUri . '?' . http_build_query($getParams) . '>; rel="previous"';
455         }
456 
457         if($p_currentPage < $totalPages)
458         {
459             $getParams['page']  = $p_currentPage + 1;
460             $linksArray['next'] = '<' . $baseLinkUri . '?' . http_build_query($getParams) . '>; rel="next"';
461 
462             $getParams['page']  = $totalPages;
463             $linksArray['last'] = '<' . $baseLinkUri . '?' . http_build_query($getParams) . '>; rel="last"';
464         }
465 
466         $this->api->response->headers->set('Link', implode(',' . PHP_EOL, $linksArray));
467     }
468     
469     
470     /**
471      * @param string $jsonString The json formatted string which should be updated.
472      * @param string $property   The name or key of the property which should be updated.
473      * @param string $value      The new value which should be set.
474      *
475      * @return string The updated json formatted string.
476      */
477     protected function _setJsonValue($jsonString, $property, $value)
478     {
479         $json = json_decode($jsonString);
480         
481         $json->$property = $value;
482         
483         return json_encode($json);
484     }
485 }
API documentation generated by ApiGen