...
Map with User Resource
If the data source has a set of "user_" prefix key and `user` property, It auto combine field to UserResource and Map to user property of the current resource
Manual mapping
Use We can override or manual mapping fields use Setter and Getter methods. Setter method uses to control input data, Getter control the output. The naming convention of setter & getter methods follow examples bellowAll field
Resource's property name | Setter method | Getter method |
---|---|---|
name | setName() | getName() |
short_description | setShortDescription() | getShortDescription() |
is_approved | setIsApproved() | getIsApproved() |
All fields query from the database table has a String data type. But Native App requires to return exactly data type in JSON.
Override "loadMetadataSchema" method of resource to control the response data type.
Following is an example:
Code Block |
---|
<?php /* A lot of code above */ class PostResource extends ResourceBase { /* ... */ protected function loadMetadataSchema(ResourceMetadata $metadata = null) { parent::loadMetadataSchema($metadata); $this->metadata ->mapField('title', ['type' => ResourceMetadata::STRING]) ->mapField('description', ['type' => ResourceMetadata::STRING]) ->mapField('item_id', ['type' => ResourceMetadata::INTEGER]) ->mapField('module_id', ['type' => ResourceMetadata::STRING]) ->mapField('is_approved', ['type' => ResourceMetadata::BOOL]) ->mapField('is_sponsor', ['type' => ResourceMetadata::BOOL]) ->mapField('is_featured', ['type' => ResourceMetadata::BOOL]) ->mapField('is_liked', ['type' => ResourceMetadata::BOOL]) ->mapField('is_friend', ['type' => ResourceMetadata::BOOL]) ->mapField('post_status', ['type' => ResourceMetadata::INTEGER]); } } |
...
Code Block |
---|
<?php /* A lot of code above */ class PostResource extends ResourceBase { /* ... */ /** Get detail url @return string */ public function getLink() { return \Phpfox::permalink('post', $this->id, $this->title); } public function getImage() { return Image::createFrom([ 'file' => $this->rawData['image_path'], 'server_id' => $this->rawData['server_id'], 'path' => 'post.url_photo', 'suffix' => '_1024' ]); } /** @return array @throws \Exception */ public function getCategories() { return $this->categories; } public function getTags() { return $this->tags; } public function getText() { if (empty($this->text) && !empty($this->rawData['text'])) { $this->text = $this->rawData['text']; } TextFilter::pureHtml($this->text, true); return $this->text; } /* ... */ } |
Define API service to handle API requests
...
Code Block |
---|
<?php namespace Apps\Posts\Service; /* ... */ class PostApi extends AbstractResourceApi implements ActivityFeedInterface, MobileAppSettingInterface { /** @var Post */ private $postService; /** @var Process */ private $processService; /** @var Category */ private $categoryService; /** @var \User_Service_User */ private $userService; public function __construct() { parent::__construct(); $this->postService = Phpfox::getService("post"); $this->categoryService = Phpfox::getService('post.category'); $this->processService = Phpfox::getService('post.process'); $this->userService = Phpfox::getService('user'); } /* .. */ } |
In
Describe the example above:
- The PostApi class extent AbstractResourceApi to reuse resource base featureall features
- Implement ActivityFeedInterface to able display the resource to Activity Feed page
- Implement MobileAppSettingInterface to register more screens and actions to Mobile App without change code
Now you need to implement all abstract method from parent class and interfaces.
The initial code of your service would look like bellowlike below:
PostApi.php
Code Block |
---|
<?php namespace Apps\Posts\Service; /* ... */ class PostApi extends AbstractResourceApi implements ActivityFeedInterface, MobileAppSettingInterface { /** * Get list post * * @param array $params * @return array|mixed * @throws ValidationErrorException */ function findAll($params = []) { /* ... */ $aItems = $this->browse()->getRows(); if ($aItems) { $this->processRows($aItems); } return $this->success($aItems); } /** * @param $params * @return array|bool */ function findOne($params) { $id = $this->resolver->resolveId($params); /* ... */ return $this->success($resource->loadFeedParam()->toArray()); } public function delete($params) { $id = $this->resolver->resolveId($params); $result = Phpfox::getService('post.process')->delete($id); if ($result !== false) { return $this->success([ 'id' => $id ]); } return $this->error('Cannot delete post'); } /** * Get Create/Update document form * @param array $params * @return mixed * @throws \Exception */ public function form($params = []) { /** @var PostForm $form */ $form = $this->createForm(PostForm::class, [ 'title' => 'adding_a_new_post', 'method' => 'post', 'action' => UrlUtility::makeApiUrl('post') ]); /* ... */ return $this->success($form->getFormStructure()); } /** * Create a new Post API * @param array $params * @return array|bool|mixed */ public function create($params = []) { /* ... */ } /** * Update a post * * @param $params * @return mixed */ public function update($params) { /* ... */ } /** * @param $id * @param bool $returnResource * @return array|PostResource */ function loadResourceById($id, $returnResource = false) { $item = Phpfox::getService("post")->getPost($id); if (empty($item['post_id'])) { return null; } if ($returnResource) { return $this->processOne($item); } return $item; } /** * Update multiple document base on document query * * @param $params * @return mixed * @throws \Exception */ public function patchUpdate($params) { /* ... */ } /** * Get for display on activity feed * @param array $feed * @param array $item detail data from database * @return array */ public function getFeedDisplay($feed, $item) { /* ... */ } /** * Create custom access control layer */ public function createAccessControl() { $this->accessControl = new PostAccessControl($this->getSetting(), $this->getUser()); /* ... */ } /** * @param array $params * @return mixed */ function searchForm($params = []) { $this->denyAccessUnlessGranted(PostAccessControl::VIEW); /** @var PostSearchForm $form */ $form = $this->createForm(PostSearchForm::class, [ 'title' =>'search', 'method' => 'GET', 'action' => UrlUtility::makeApiUrl('post') ]); return $this->success($form->getFormStructure()); } public function getRouteMap() { /* ... */ } /** * @param $param * @return MobileApp */ public function getAppSetting($param) { /* ... */ } } |
...
Code Block |
---|
<?php /* ... */ Phpfox::getLib('module') ->addAliasNames('post', 'Posts') ->addServiceNames([ // New API service register here 'mobile.post_api' => Service\PostApi::class, 'mobile.post_category_api' => Service\PostCategoryApi::class, // Other Services of the app 'post.category' => Service\Category\Category::class, 'post.category.process' => Service\Category\Process::class, 'post.api' => Service\Api::class, 'post' => Service\Posts::class, 'post.browse' => Service\Browse::class, 'post.cache.remove' => Service\Cache\Remove::class, 'post.callback' => Service\Callback::class, 'post.process' => Service\Process::class, 'post.permission' => Service\Permission::class, ]); /* ... */ |
...
Code Block |
---|
<?php class PostApi extends AbstractResourceApi implements ActivityFeedInterface, MobileAppSettingInterface { /** This method allow you add custom route for APIs Return an array with key is routing rule and mapping condition In this case, 'mobile/post/search-form' map to `searchForm` method */ public function __naming() { return [ 'post/search-form'=> [ 'get'=>'searchForm' ] ]; } /** @param array $params @return mixed */ function searchForm($params = []) { $this->denyAccessUnlessGranted(PostAccessControl::VIEW); /** @var PostSearchForm $form */ $form = $this->createForm(PostSearchForm::class, [ 'title' =>'search', 'method' => 'GET', 'action' => UrlUtility::makeApiUrl('post') ]); return $this->success($form->getFormStructure()); } } |
You can download the full sample code of Post API service.
...