/** * Get access path to element which works with PropertyAccessor. * * @param string $elementId expects string in format used in form id field. (uniqueIdentifier_model_sub_model or uniqueIdentifier_model_1_sub_model etc.) * @param mixed $entity * * @return string * * @throws \Exception */ public function getElementAccessPath($elementId, $entity) { $propertyAccessor = $this->pool->getPropertyAccessor(); $idWithoutIdentifier = preg_replace('/^[^_]*_/', '', $elementId); $initialPath = preg_replace('#(_(\\d+)_)#', '[$2]_', $idWithoutIdentifier); $parts = explode('_', $initialPath); $totalPath = ''; $currentPath = ''; foreach ($parts as $part) { $currentPath .= empty($currentPath) ? $part : '_' . $part; $separator = empty($totalPath) ? '' : '.'; if ($this->pathExists($propertyAccessor, $entity, $totalPath . $separator . $currentPath)) { $totalPath .= $separator . $currentPath; $currentPath = ''; } } if (!empty($currentPath)) { throw new \Exception(sprintf('Could not get element id from %s Failing part: %s', $elementId, $currentPath)); } return $totalPath; }
/** * Get access path to element which works with PropertyAccessor. * * @param string $elementId expects string in format used in form id field. (uniqueIdentifier_model_sub_model or uniqueIdentifier_model_1_sub_model etc.) * @param mixed $entity * * @return string * * @throws \Exception */ public function getElementAccessPath($elementId, $entity) { $propertyAccessor = $this->pool->getPropertyAccessor(); $idWithoutUniqueIdentifier = implode('_', explode('_', substr($elementId, strpos($elementId, '_') + 1))); //array access of id converted to format which PropertyAccessor understands $initialPath = preg_replace('#(_(\\d+)_)#', '[$2]', $idWithoutUniqueIdentifier); $parts = preg_split('#\\[\\d+\\]#', $initialPath); $partReturnValue = $returnValue = ''; $currentEntity = $entity; foreach ($parts as $key => $value) { $subParts = explode('_', $value); $id = ''; $dot = ''; foreach ($subParts as $subValue) { $id .= $id ? '_' . $subValue : $subValue; if ($this->pathExists($propertyAccessor, $currentEntity, $partReturnValue . $dot . $id)) { $partReturnValue .= $dot . $id; $dot = '.'; $id = ''; } else { $dot = ''; } } if ($dot !== '.') { throw new \Exception(sprintf('Could not get element id from %s Failing part: %s', $elementId, $subValue)); } //check if array access was in this location originally preg_match("#{$value}\\[(\\d+)#", $initialPath, $matches); if (isset($matches[1])) { $partReturnValue .= '[' . $matches[1] . ']'; } $returnValue .= $returnValue ? '.' . $partReturnValue : $partReturnValue; $partReturnValue = ''; if (isset($parts[$key + 1])) { $currentEntity = $propertyAccessor->getValue($entity, $returnValue); } } return $returnValue; }
/** * @throws \RunTimeException * * @param mixed $element * @param FieldDescriptionInterface $fieldDescription * * @return mixed */ public function renderRelationElement($element, FieldDescriptionInterface $fieldDescription) { if (!is_object($element)) { return $element; } $propertyPath = $fieldDescription->getOption('associated_property'); if (null === $propertyPath) { // For BC kept associated_tostring option behavior $method = $fieldDescription->getOption('associated_tostring'); if ($method) { @trigger_error('Option "associated_tostring" is deprecated since version 2.3. Use "associated_property" instead.', E_USER_DEPRECATED); } else { $method = '__toString'; } if (!method_exists($element, $method)) { throw new \RuntimeException(sprintf('You must define an `associated_property` option or ' . 'create a `%s::__toString` method to the field option %s from service %s is ', get_class($element), $fieldDescription->getName(), $fieldDescription->getAdmin()->getCode())); } return call_user_func(array($element, $method)); } if (is_callable($propertyPath)) { return $propertyPath($element); } return $this->pool->getPropertyAccessor()->getValue($element, $propertyPath); }
/** * @param Request $request * * @return Response */ public function setObjectFieldValueAction(Request $request) { $field = $request->get('field'); $code = $request->get('code'); $objectId = $request->get('objectId'); $value = $request->get('value'); $context = $request->get('context'); $admin = $this->pool->getInstance($code); $admin->setRequest($request); // alter should be done by using a post method if (!$request->isXmlHttpRequest()) { return new JsonResponse(array('status' => 'KO', 'message' => 'Expected a XmlHttpRequest request header')); } if ($request->getMethod() != 'POST') { return new JsonResponse(array('status' => 'KO', 'message' => 'Expected a POST Request')); } $rootObject = $object = $admin->getObject($objectId); if (!$object) { return new JsonResponse(array('status' => 'KO', 'message' => 'Object does not exist')); } // check user permission if (false === $admin->isGranted('EDIT', $object)) { return new JsonResponse(array('status' => 'KO', 'message' => 'Invalid permissions')); } if ($context == 'list') { $fieldDescription = $admin->getListFieldDescription($field); } else { return new JsonResponse(array('status' => 'KO', 'message' => 'Invalid context')); } if (!$fieldDescription) { return new JsonResponse(array('status' => 'KO', 'message' => 'The field does not exist')); } if (!$fieldDescription->getOption('editable')) { return new JsonResponse(array('status' => 'KO', 'message' => 'The field cannot be edit, editable option must be set to true')); } $propertyPath = new PropertyPath($field); // If property path has more than 1 element, take the last object in order to validate it if ($propertyPath->getLength() > 1) { $object = $this->pool->getPropertyAccessor()->getValue($object, $propertyPath->getParent()); $elements = $propertyPath->getElements(); $field = end($elements); $propertyPath = new PropertyPath($field); } // Handle date type has setter expect a DateTime object if ('' !== $value && $fieldDescription->getType() == 'date') { $value = new \DateTime($value); } $this->pool->getPropertyAccessor()->setValue($object, $propertyPath, '' !== $value ? $value : null); $violations = $this->validator->validate($object); if (count($violations)) { $messages = array(); foreach ($violations as $violation) { $messages[] = $violation->getMessage(); } return new JsonResponse(array('status' => 'KO', 'message' => implode("\n", $messages))); } $admin->update($object); // render the widget // todo : fix this, the twig environment variable is not set inside the extension ... $extension = $this->twig->getExtension('sonata_admin'); $extension->initRuntime($this->twig); $content = $extension->renderListElement($rootObject, $fieldDescription); return new JsonResponse(array('status' => 'OK', 'content' => $content)); }