pimcore/lib/Pimcore/Bundle/AdminBundle/Controller/Rest/Element/DataObjectController.php line 406

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\Controller\Rest\Element;
  15. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  16. use Pimcore\Http\Exception\ResponseException;
  17. use Pimcore\Model\DataObject;
  18. use Pimcore\Model\Webservice\Data\DataObject\Concrete\In as WebserviceObjectIn;
  19. use Pimcore\Model\Webservice\Data\DataObject\Concrete\Out as WebserviceObjectOut;
  20. use Pimcore\Model\Webservice\Data\DataObject\Folder\In as WebserviceFolderIn;
  21. use Pimcore\Model\Webservice\Data\DataObject\Folder\Out as WebserviceFolderOut;
  22. use Pimcore\Tool;
  23. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  24. use Symfony\Component\HttpFoundation\Request;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use Symfony\Component\Stopwatch\Stopwatch;
  27. /**
  28.  * end point for object related data.
  29.  *
  30.  * - get object by id
  31.  *      GET http://[YOUR-DOMAIN]/webservice/rest/object/id/1281?apikey=[API-KEY]
  32.  *      returns json-encoded object data.
  33.  * - delete object by id
  34.  *      DELETE http://[YOUR-DOMAIN]/webservice/rest/object/id/1281?apikey=[API-KEY]
  35.  *      returns json encoded success value
  36.  * - create object
  37.  *      PUT or POST http://[YOUR-DOMAIN]/webservice/rest/object?apikey=[API-KEY]
  38.  *      body: json-encoded object data in the same format as returned by get object by id
  39.  *              but with missing id field or id set to 0
  40.  *      returns json encoded object id
  41.  * - update object
  42.  *      PUT or POST http://[YOUR-DOMAIN]/webservice/rest/object/id/1281?apikey=[API-KEY]
  43.  *      body: same as for create object. object id can be either in URI or as request payload
  44.  *      returns json encoded success value
  45.  */
  46. class DataObjectController extends AbstractElementController
  47. {
  48.     /**
  49.      * @Method("GET")
  50.      * @Route("/object/id/{id}", requirements={"id": "\d+"})
  51.      * @Route("/object")
  52.      *
  53.      * @api {get} /object Get object data
  54.      * @apiName Get object by id
  55.      * @apiGroup Object
  56.      * @apiSampleRequest off
  57.      * @apiParam {int} id an object id
  58.      * @apiParam {string} apikey your access token
  59.      * @apiParamExample {json} Request-Example:
  60.      *     {
  61.      *         "id": 1,
  62.      *         "apikey": "21314njdsfn1342134"
  63.      *      }
  64.      * @apiSuccess {json} success parameter of the returned data = true
  65.      * @apiError {json} success parameter of the returned data = false
  66.      * @apiErrorExample {json} Error-Response:
  67.      *                  {"success":false, "msg":"exception 'Exception' with message '....'"}
  68.      * @apiSuccessExample {json} Success-Response:
  69.      *                    HTTP/1.1 200 OK
  70.      *                    {
  71.      *                      "success": true
  72.      *                      "data": {
  73.      *                       "path": "/crm/inquiries/",
  74.      *                       "creationDate": 1368630916,
  75.      *                       "modificationDate": 1388409137,
  76.      *                       "userModification": null,
  77.      *                       "childs": null,
  78.      *                       "elements": [
  79.      *                       {
  80.      *                           "type": "gender",
  81.      *                           "value": "female",
  82.      *                           "name": "gender",
  83.      *                           "language": null
  84.      *                      },
  85.      *
  86.      *                      ...
  87.      *
  88.      *                    }
  89.      *
  90.      * @param Request  $request
  91.      * @param int|null $id
  92.      *
  93.      * @return JsonResponse
  94.      *
  95.      * @throws ResponseException
  96.      */
  97.     public function getAction(Request $request$id null)
  98.     {
  99.         $id $this->resolveId($request$id);
  100.         $profile     $request->get('profiling');
  101.         $profileName 'rest_object_get';
  102.         /** @var Stopwatch $stopwatch */
  103.         $stopwatch null;
  104.         if ($profile) {
  105.             $stopwatch $this->startProfiling();
  106.             $stopwatch->start('get'$profileName);
  107.         }
  108.         $object $this->loadObject($id);
  109.         if ($profile) {
  110.             $stopwatch->stop('get');
  111.             $stopwatch->start('perm'$profileName);
  112.         }
  113.         $this->checkElementPermission($object'get');
  114.         if ($profile) {
  115.             $stopwatch->stop('perm');
  116.             $stopwatch->start('ws'$profileName);
  117.         }
  118.         /** @var WebserviceObjectOut|WebserviceFolderOut $out */
  119.         if ($object instanceof DataObject\Folder) {
  120.             $out $this->service->getObjectFolderById($id);
  121.         } else {
  122.             $out $this->service->getObjectConcreteById($id);
  123.         }
  124.         if ($profile) {
  125.             $stopwatch->stop('ws');
  126.         }
  127.         $data $this->createSuccessData($out);
  128.         if ($profile) {
  129.             $data['profiling'] = $this->getProfilingData($profileName);
  130.         }
  131.         return $this->adminJson($data);
  132.     }
  133.     /**
  134.      * @Method({"POST", "PUT"})
  135.      * @Route("/object")
  136.      *
  137.      * @api {post} /object Create a new object
  138.      * @apiName Create a new object
  139.      * @apiGroup Object
  140.      * @apiSampleRequest off
  141.      * @apiDescription
  142.      * Request body: JSON-encoded object data in the same format as returned by get object by id for the data segment but with missing id field or id set to 0
  143.      *
  144.      * @apiParam {json} data a new object data
  145.      * @apiParam {string} apikey your access token
  146.      * @apiParamExample {json} Request-Example:
  147.      *     {
  148.      *         "apikey": "21314njdsfn1342134",
  149.      *         "data": {
  150.      *               "id": 61,
  151.      *               "parentId": 48,
  152.      *               "key": "test-product-key",
  153.      *               "className": "product",
  154.      *               "type": "object",
  155.      *               "elements": [
  156.      *                   {
  157.      *                   "type": "input",
  158.      *                   "value": "some identyfier",
  159.      *                   "name": "identyfier",
  160.      *                   "language": null
  161.      *                   },
  162.      *                   {
  163.      *                   "type": "localizedfields",
  164.      *                   "value": [
  165.      *                   {
  166.      *                   "type": "input",
  167.      *                   "value": "Test",
  168.      *                   "name": "name1",
  169.      *                   "language": "en"
  170.      *                   },
  171.      *                   {
  172.      *                   "type": "input",
  173.      *                   "value": "1",
  174.      *                   "name": "name2",
  175.      *                   "language": "en"
  176.      *                   },
  177.      *                   {
  178.      *                   "type": "input",
  179.      *                   "value": null,
  180.      *                   "name": "name1",
  181.      *                   "language": "de"
  182.      *                   },
  183.      *                   {
  184.      *                   "type": "input",
  185.      *                   "value": "aaa",
  186.      *                   "name": "name2",
  187.      *                   "language": "de"
  188.      *                   }
  189.      *                   ],
  190.      *                   "name": "localizedfields",
  191.      *                   "language": null
  192.      *                       }
  193.      *               ]
  194.      *           }
  195.      *     }
  196.      * @apiSuccess {json} success parameter of the returned data = true
  197.      * @apiError {json} success parameter of the returned data = false
  198.      * @apiErrorExample {json} Error-Response:
  199.      *                  {"success":false, "msg":"exception 'Exception' with message '....'"}
  200.      * @apiSuccessExample {json} Success-Response:
  201.      *                    HTTP/1.1 200 OK
  202.      *                    {
  203.      *                      "success": true
  204.      *                    }
  205.      *
  206.      * @param Request $request
  207.      *
  208.      * @return JsonResponse
  209.      */
  210.     public function createAction(Request $request)
  211.     {
  212.         $data $this->getJsonData($request);
  213.         // get and normalize type
  214.         $type $data['type'] = isset($data['type']) ? $data['type'] : 'object';
  215.         // add support for legacy behaviour, accepting the ID as payload parameter
  216.         if (isset($data['id'])) {
  217.             $id     $data['id'];
  218.             $object $this->loadObject($id);
  219.             return $this->updateObject($object$type$data);
  220.         }
  221.         return $this->createObject($type$data);
  222.     }
  223.     /**
  224.      * @Method({"POST", "PUT"})
  225.      * @Route("/object/id/{id}", requirements={"id": "\d+"})
  226.      *
  227.      * @api {put} /object/id/{id} Update an object
  228.      * @apiName Create a new object
  229.      * @apiGroup Object
  230.      * @apiSampleRequest off
  231.      * @apiDescription
  232.      * Request body: JSON-encoded object data in the same format as returned by get object by id for the data segment but with missing id field or id set to 0
  233.      *
  234.      * @apiParam {json} data a new object data
  235.      * @apiParam {string} apikey your access token
  236.      * @apiParamExample {json} Request-Example:
  237.      *     {
  238.      *         "apikey": "21314njdsfn1342134",
  239.      *         "id": 66
  240.      *         "data": {
  241.      *               "parentId": 48,
  242.      *               "key": "test-product-key",
  243.      *               "className": "product",
  244.      *               "type": "object",
  245.      *               "elements": [
  246.      *                   {
  247.      *                   "type": "input",
  248.      *                   "value": "some identyfier",
  249.      *                   "name": "identyfier",
  250.      *                   "language": null
  251.      *                   },
  252.      *                   {
  253.      *                   "type": "localizedfields",
  254.      *                   "value": [
  255.      *                   {
  256.      *                   "type": "input",
  257.      *                   "value": "Test new",
  258.      *                   "name": "name1",
  259.      *                   "language": "en"
  260.      *                   },
  261.      *                   {
  262.      *                   "type": "input",
  263.      *                   "value": "1",
  264.      *                   "name": "name2",
  265.      *                   "language": "en"
  266.      *                   },
  267.      *                   {
  268.      *                   "type": "input",
  269.      *                   "value": null,
  270.      *                   "name": "name1",
  271.      *                   "language": "de"
  272.      *                   },
  273.      *                   {
  274.      *                   "type": "input",
  275.      *                   "value": "aaa",
  276.      *                   "name": "name2",
  277.      *                   "language": "de"
  278.      *                   }
  279.      *                   ],
  280.      *                   "name": "localizedfields",
  281.      *                   "language": null
  282.      *                       }
  283.      *               ]
  284.      *           }
  285.      *     }
  286.      * @apiSuccess {json} success parameter of the returned data = true
  287.      * @apiError {json} success parameter of the returned data = false
  288.      * @apiErrorExample {json} Error-Response:
  289.      *                  {"success":false, "msg":"exception 'Exception' with message '....'"}
  290.      * @apiSuccessExample {json} Success-Response:
  291.      *                    HTTP/1.1 200 OK
  292.      *                    {
  293.      *                      "success": true,
  294.      *                      "id": 66
  295.      *                    }
  296.      *
  297.      * @param Request  $request
  298.      * @param int|null $id
  299.      *
  300.      * @return JsonResponse
  301.      */
  302.     public function updateAction(Request $request$id)
  303.     {
  304.         $id   $this->resolveId($request$id);
  305.         $data $this->getJsonData($request);
  306.         // get and normalize type
  307.         $type $data['type'] = isset($data['type']) ? $data['type'] : 'object';
  308.         $object $this->loadObject($id);
  309.         return $this->updateObject($object$type$data);
  310.     }
  311.     /**
  312.      * @Method("DELETE")
  313.      * @Route("/object/id/{id}", requirements={"id": "\d+"})
  314.      * @Route("/object")
  315.      *
  316.      * @api {delete} /object/id/{id} Delete object
  317.      * @apiName Delete object
  318.      * @apiGroup Object
  319.      * @apiSampleRequest off
  320.      * @apiParam {int} id an object id
  321.      * @apiParam {string} apikey your access token
  322.      * @apiParamExample {json} Request-Example:
  323.      *     {
  324.      *         "id": 1,
  325.      *         "apikey": "21314njdsfn1342134"
  326.      *     }
  327.      * @apiSuccess {json} success parameter of the returned data = true
  328.      * @apiError {json} success parameter of the returned data = false
  329.      * @apiErrorExample {json} Error-Response:
  330.      *                  {"success":false, "msg":"exception 'Exception' with message '....'"}
  331.      * @apiSuccessExample {json} Success-Response:
  332.      *                    HTTP/1.1 200 OK
  333.      *                    {
  334.      *                      "success": true,
  335.      *                    }
  336.      *
  337.      * @param Request  $request
  338.      * @param int|null $id
  339.      *
  340.      * @return JsonResponse
  341.      *
  342.      * @throws ResponseException
  343.      */
  344.     public function deleteAction(Request $request$id null)
  345.     {
  346.         $id     $this->resolveId($request$id);
  347.         $object $this->loadObject($id);
  348.         $this->checkElementPermission($object'delete');
  349.         $success $this->service->deleteObject($id);
  350.         if ($success) {
  351.             return $this->createSuccessResponse();
  352.         } else {
  353.             // TODO what to do on delete error? is bad request appropiate?
  354.             return $this->createErrorResponse();
  355.         }
  356.     }
  357.     /**
  358.      * @Method("GET")
  359.      * @Route("/object-list")
  360.      *
  361.      * Returns a list of object id/type pairs matching the given criteria.
  362.      *  Example:
  363.      *  GET http://[YOUR-DOMAIN]/webservice/rest/object-list?apikey=[API-KEY]&order=DESC&offset=3&orderKey=id&limit=2&condition=type%3D%27folder%27
  364.      *
  365.      * Parameters:
  366.      *      - condition
  367.      *      - sort order (if supplied then also the key must be provided)
  368.      *      - sort order key
  369.      *      - offset
  370.      *      - limit
  371.      *      - group by key
  372.      *      - objectClass the name of the object class (without "Object_"). If the class does
  373.      *          not exist the filter criteria will be ignored!
  374.      *
  375.      * @param Request $request
  376.      *
  377.      * @return JsonResponse
  378.      */
  379.     public function listAction(Request $request)
  380.     {
  381.         $this->checkPermission('objects');
  382.         $condition   urldecode($request->get('condition'));
  383.         $order       $request->get('order');
  384.         $orderKey    $request->get('orderKey');
  385.         $offset      $request->get('offset');
  386.         $limit       $request->get('limit');
  387.         $groupBy     $request->get('groupBy');
  388.         $objectClass $request->get('objectClass');
  389.         $result $this->service->getObjectList($condition$order$orderKey$offset$limit$groupBy$objectClass);
  390.         return $this->createCollectionSuccessResponse($result);
  391.     }
  392.     /**
  393.      * @Method("GET")
  394.      * @Route("/object-meta/id/{id}", requirements={"id": "\d+"})
  395.      *
  396.      * end point for object metadata
  397.      *  Example:
  398.      *  GET http://[YOUR-DOMAIN]/webservice/rest/object-meta/id/1281?apikey=[API-KEY]
  399.      *      returns the json-encoded class definition for the given object
  400.      *
  401.      * @param int $id
  402.      *
  403.      * @return JsonResponse
  404.      *
  405.      * @throws ResponseException
  406.      */
  407.     public function objectMetaAction($id)
  408.     {
  409.         $this->checkPermission('classes');
  410.         $class $this->service->getObjectMetadataById($id);
  411.         if (!$class) {
  412.             throw $this->createNotFoundResponseException();
  413.         }
  414.         return $this->createSuccessResponse($class);
  415.     }
  416.     /**
  417.      * @Method("GET")
  418.      * @Route("/object-count")
  419.      *
  420.      * Returns the total number of objects matching the given condition
  421.      *  Example:
  422.      *  GET http://[YOUR-DOMAIN]/webservice/rest/object-count?apikey=[API-KEY]&condition=type%3D%27folder%27
  423.      *
  424.      * Parameters:
  425.      *      - condition
  426.      *      - group by key
  427.      *      - objectClass the name of the object class (without "Object_"). If the class does
  428.      *          not exist the filter criteria will be ignored!
  429.      *
  430.      * @param Request $request
  431.      *
  432.      * @return JsonResponse
  433.      */
  434.     public function countAction(Request $request)
  435.     {
  436.         $this->checkPermission('objects');
  437.         $condition   urldecode($request->get('condition'));
  438.         $groupBy     $request->get('groupBy');
  439.         $objectClass $request->get('objectClass');
  440.         $params = [
  441.             'objectTypes' => [
  442.                 DataObject\AbstractObject::OBJECT_TYPE_FOLDER,
  443.                 DataObject\AbstractObject::OBJECT_TYPE_OBJECT,
  444.                 DataObject\AbstractObject::OBJECT_TYPE_VARIANT
  445.             ]
  446.         ];
  447.         if (!empty($condition)) {
  448.             $params['condition'] = $condition;
  449.         }
  450.         if (!empty($groupBy)) {
  451.             $params['groupBy'] = $groupBy;
  452.         }
  453.         $listClassName DataObject\AbstractObject::class;
  454.         if (!empty($objectClass)) {
  455.             $listClassName '\\Pimcore\\Model\\DataObject\\' ucfirst($objectClass);
  456.             if (!Tool::classExists($listClassName)) {
  457.                 $listClassName DataObject\AbstractObject::class;
  458.             }
  459.         }
  460.         $count $listClassName::getTotalCount($params);
  461.         return $this->createSuccessResponse([
  462.             'totalCount' => $count
  463.         ]);
  464.     }
  465.     /**
  466.      * @Method({"GET", "POST"})
  467.      * @Route("/object-inquire")
  468.      *
  469.      * Checks for existence of the given object IDs
  470.      *
  471.      *  GET http://[YOUR-DOMAIN]/webservice/rest/object-inquire?apikey=[API-KEY]
  472.      *
  473.      * Parameters:
  474.      *      - id single object ID
  475.      *      - ids comma separated list of object IDs
  476.      * Returns:
  477.      *      - List with true or false for each ID
  478.      *
  479.      * @param Request $request
  480.      *
  481.      * @return JsonResponse
  482.      */
  483.     public function inquireAction(Request $request)
  484.     {
  485.         return $this->inquire($request'object');
  486.     }
  487.     /**
  488.      * @param int $id
  489.      *
  490.      * @return DataObject\AbstractObject
  491.      *
  492.      * @throws ResponseException
  493.      *      if object was not found
  494.      */
  495.     protected function loadObject($id)
  496.     {
  497.         $object DataObject::getById((int)$id);
  498.         if ($object) {
  499.             return $object;
  500.         }
  501.         throw $this->createNotFoundResponseException([
  502.             'msg'  => sprintf('Object %d does not exist', (int)$id),
  503.             'code' => static::ELEMENT_DOES_NOT_EXIST
  504.         ]);
  505.     }
  506.     /**
  507.      * Create an object
  508.      *
  509.      * @param string $type
  510.      * @param array $data
  511.      *
  512.      * @return JsonResponse
  513.      */
  514.     protected function createObject($type, array $data)
  515.     {
  516.         if ($type === 'folder') {
  517.             $class  WebserviceFolderIn::class;
  518.             $method 'createObjectFolder';
  519.         } else {
  520.             $class  WebserviceObjectIn::class;
  521.             $method 'createObjectConcrete';
  522.         }
  523.         $wsData $this->fillWebserviceData($class$data);
  524.         $object = new DataObject();
  525.         $object->setId($wsData->parentId);
  526.         $this->checkElementPermission($object'create');
  527.         $id $this->service->$method($wsData);
  528.         if (null !== $id) {
  529.             return $this->createSuccessResponse([
  530.                 'id' => $id
  531.             ], false);
  532.         } else {
  533.             return $this->createErrorResponse();
  534.         }
  535.     }
  536.     /**
  537.      * Update an existing object
  538.      *
  539.      * @param DataObject\AbstractObject $object
  540.      * @param string $type
  541.      * @param array $data
  542.      *
  543.      * @return JsonResponse
  544.      */
  545.     protected function updateObject(DataObject\AbstractObject $object$type, array $data)
  546.     {
  547.         $this->checkElementPermission($object'update');
  548.         $data['id'] = $object->getId();
  549.         $success false;
  550.         if ($type === 'folder') {
  551.             $wsData  $this->fillWebserviceData(WebserviceFolderIn::class, $data);
  552.             $success $this->service->updateObjectFolder($wsData);
  553.         } else {
  554.             $wsData  $this->fillWebserviceData(WebserviceObjectIn::class, $data);
  555.             $success $this->service->updateObjectConcrete($wsData);
  556.         }
  557.         if ($success) {
  558.             return $this->createSuccessResponse();
  559.         } else {
  560.             return $this->createErrorResponse();
  561.         }
  562.     }
  563. }