/** * Creates operation. * * @param ResourceInterface $resource * @param bool $collection * @param string|array $methods * @param string|null $path * @param string|null $controller * @param string|null $routeName * @param array $context * * @return Operation */ private function createOperation(ResourceInterface $resource, $collection, $methods, $path = null, $controller = null, $routeName = null, array $context = []) { $shortName = $resource->getShortName(); if (!isset(self::$inflectorCache[$shortName])) { self::$inflectorCache[$shortName] = Inflector::pluralize(Inflector::tableize($shortName)); } // Populate path if (null === $path) { $path = '/' . self::$inflectorCache[$shortName]; if (!$collection) { $path .= '/{id}'; } } // Guess default method if (is_array($methods)) { $defaultMethod = $methods[0]; } else { $defaultMethod = $methods; } // Populate controller if (null === $controller) { $defaultAction = strtolower($defaultMethod); if ($collection) { $defaultAction = 'c' . $defaultAction; } $controller = self::DEFAULT_CONTROLLER . ':' . $defaultAction; // Populate route name if (null === $routeName) { $routeName = self::ROUTE_NAME_PREFIX . self::$inflectorCache[$shortName] . '_' . $defaultAction; } } return new Operation(new Route($path, ['_controller' => $controller, '_resource' => $shortName], [], [], '', [], $methods), $routeName, $context); }
/** * Creates normalization context. * * @param ResourceInterface $resource * @param array $context * * @return array */ private function createContext(ResourceInterface $resource, $context) { if (!isset($context['jsonld_has_context'])) { $context += ['resource' => $resource, 'jsonld_has_context' => true, 'jsonld_sub_level' => true, 'jsonld_normalization_groups' => $resource->getNormalizationGroups(), 'jsonld_denormalization_groups' => $resource->getDenormalizationGroups(), 'jsonld_validation_groups' => $resource->getValidationGroups()]; } return $context; }
/** * Creates operation. * * @param ResourceInterface $resource * @param bool $collection * @param string|array $methods * @param string|null $path * @param string|null $controller * @param string|null $routeName * @param array $context * * @return Operation */ private function createOperation(ResourceInterface $resource, $collection, $methods, $path = null, $controller = null, $routeName = null, array $context = []) { $shortName = $resource->getShortName(); if (!isset(self::$inflectorCache[$shortName])) { self::$inflectorCache[$shortName] = Inflector::pluralize(Inflector::tableize($shortName)); } // Populate path if (null === $path) { $path = '/' . self::$inflectorCache[$shortName]; if (!$collection) { $path .= '/{id}'; } } // Guess default method if (is_array($methods)) { $defaultMethod = $methods[0]; } else { $defaultMethod = $methods; } // Populate controller if (null === $controller) { $actionName = sprintf('%s_%s', strtolower($defaultMethod), $collection ? 'collection' : 'item'); $controller = self::DEFAULT_ACTION_PATTERN . $actionName; // Populate route name if (null === $routeName) { $routeName = sprintf('%s%s_%s', self::ROUTE_NAME_PREFIX, self::$inflectorCache[$shortName], $actionName); } } return new Operation(new Route($path, ['_controller' => $controller, '_resource' => $shortName], [], [], '', [], $methods), $routeName, $context); }
/** * {@inheritdoc} * * @return Folder */ public function generate(ResourceInterface $resource = null) { $folder = new Folder(); $folder->setId((string) Uuid::uuid4()); $folder->setName($resource->getShortName()); return $folder; }
/** * Gets the manager if applicable. * * @param ResourceInterface $resourceType * @param mixed $data * * @return ObjectManager|null */ private function getManager(ResourceInterface $resourceType, $data) { $objectManager = $this->managerRegistry->getManagerForClass($resourceType->getEntityClass()); if (null === $objectManager || !is_object($data)) { return; } return $objectManager; }
/** * {@inheritdoc} */ public function applyToCollection(ResourceInterface $resource, QueryBuilder $queryBuilder) { foreach ($resource->getFilters() as $filter) { if ($filter instanceof FilterInterface) { $filter->apply($resource, $queryBuilder); } } }
/** * {@inheritdoc} */ public function applyToCollection(ResourceInterface $resource, QueryBuilder $queryBuilder) { $classMetaData = $queryBuilder->getEntityManager()->getClassMetadata($resource->getEntityClass()); $identifiers = $classMetaData->getIdentifier(); if (null !== $this->order && 1 === count($identifiers)) { $identifier = $identifiers[0]; $queryBuilder->addOrderBy('o.' . $identifier, $this->order); } }
/** * Returns true if at least one GET collection operation exists for the given resource. * * @param ResourceInterface $resource * * @return bool */ private function hasGetCollectionOperation(ResourceInterface $resource) { foreach ($resource->getCollectionOperations() as $operation) { $methods = $operation->getRoute()->getMethods(); if (empty($methods) || in_array('GET', $methods)) { return true; } } return false; }
/** * Parses a class. * * @param ResourceInterface $resource * @param string $entityClass * @param string $io * * @return array */ private function parseClass(ResourceInterface $resource, $entityClass, $io) { $classMetadata = $this->classMetadataFactory->getMetadataFor($entityClass, $resource->getNormalizationGroups(), $resource->getDenormalizationGroups(), $resource->getValidationGroups()); $data = array(); foreach ($classMetadata->getAttributes() as $attributeMetadata) { if (!$attributeMetadata->isIdentifier() && $attributeMetadata->isReadable() && self::OUT_PREFIX === $io || $attributeMetadata->isWritable() && self::IN_PREFIX === $io) { $data[$attributeMetadata->getName()] = $this->parseAttribute($resource, $attributeMetadata, $io); } } return $data; }
/** * Left joins relations to eager load. * * @param ResourceInterface $resource * @param QueryBuilder $queryBuilder */ private function joinRelations(ResourceInterface $resource, QueryBuilder $queryBuilder) { $classMetaData = $queryBuilder->getEntityManager()->getClassMetadata($resource->getEntityClass()); foreach ($classMetaData->getAssociationNames() as $i => $association) { $mapping = $classMetaData->associationMappings[$association]; if (ClassMetadataInfo::FETCH_EAGER === $mapping['fetch']) { $queryBuilder->leftJoin('o.' . $association, 'a' . $i); $queryBuilder->addSelect('a' . $i); } } }
/** * {@inheritdoc} */ public function add(ResourceInterface $resource) { $entityClass = $resource->getEntityClass(); if (isset($this->entityClassIndex[$entityClass])) { throw new \InvalidArgumentException(sprintf('A Resource class already exists for "%s".', $entityClass)); } $shortName = $resource->getShortName(); if (isset($this->shortNameIndex[$shortName])) { throw new \InvalidArgumentException(sprintf('A Resource class with the short name "%s" already exists.', $shortName)); } $this->append($resource); $this->entityClassIndex[$entityClass] = $resource; $this->shortNameIndex[$shortName] = $resource; }
/** * @param Request $request * @param ResourceInterface $resourceEmbed * @param $data * * @return \Doctrine\Common\Collections\Collection|PersistentCollection */ public function ApplyCriteria(Request $request, ResourceInterface $resourceEmbed, $data) { if ($data instanceof PersistentCollection && $data->count() > 0) { $embedClassMeta = $this->em->getClassMetadata($resourceEmbed->getEntityClass()); $criteria = Criteria::create(); foreach ($resourceEmbed->getFilters() as $filter) { if ($filter instanceof FilterInterface) { $this->applyFilter($request, $filter, $criteria, $embedClassMeta); $data = $data->matching($criteria); } } } return $data; }
/** * Builds ApiDoc annotation from DunglasApiBundle data. * * @param bool $collection * @param ResourceInterface $resource * @param OperationInterface $operation * @param array $resourceHydraDoc * @param array $entrypointHydraDoc * * @return ApiDoc */ private function getApiDoc($collection, ResourceInterface $resource, OperationInterface $operation, array $resourceHydraDoc, array $entrypointHydraDoc = []) { $method = $operation->getRoute()->getMethods()[0]; if ($collection) { $operationHydraDoc = $this->getCollectionOperationHydraDoc($resource->getShortName(), $method, $entrypointHydraDoc); } else { $operationHydraDoc = $this->getOperationHydraDoc($operation->getRoute()->getMethods()[0], $resourceHydraDoc); } $route = $operation->getRoute(); $data = ['resource' => $route->getPath(), 'description' => $operationHydraDoc['hydra:title'], 'resourceDescription' => $resourceHydraDoc['hydra:title'], 'section' => $resourceHydraDoc['hydra:title']]; $entityClass = $resource->getEntityClass(); if (isset($operationHydraDoc['expects']) && 'owl:Nothing' !== $operationHydraDoc['expects']) { $data['input'] = sprintf('%s:%s', DunglasApiParser::IN_PREFIX, $entityClass); } if (isset($operationHydraDoc['returns']) && 'owl:Nothing' !== $operationHydraDoc['returns']) { $data['output'] = sprintf('%s:%s', DunglasApiParser::OUT_PREFIX, $entityClass); } if (Request::METHOD_GET === $method && $collection) { $data['filters'] = []; foreach ($resource->getFilters() as $filter) { foreach ($filter->getDescription($resource) as $name => $definition) { $data['filters'][] = ['name' => $name] + $definition; } } } $apiDoc = new ApiDoc($data); $apiDoc->setRoute($route); return $apiDoc; }
/** * @param ResourceInterface $resourceParent * * @return $this */ public function setResourceParent($resourceParent) { $this->resourceParent = $resourceParent; if (null !== $this->resourceParent && null === $this->parentName) { $this->parentName = $this->resourceParent->getShortName(); } return $this; }
/** * @param $object * @param ResourceInterface $dunglasResource * @param Manager $fractalManager * @param Request|null $request * @param bool $defaultIncludes * * @return array * @throws \Exception */ public function normalize($object, ResourceInterface $dunglasResource, Manager $fractalManager, Request $request = null, $defaultIncludes = true) { $transformer = $this->transformerHelper->getTransformer($dunglasResource->getShortName()); if (null !== $request) { $fractalManager->parseIncludes($this->getEmbedsWithoutOptions($transformer, $request)); } $resource = new Item($object, $transformer); if ($object instanceof Paginator || $object instanceof PersistentCollection) { $resource = new Collection($object, $transformer); if ($fractalManager->getSerializer() instanceof ArraySerializer) { $resource->setPaginator(new DunglasPaginatorAdapter($object, $resource)); } } $rootScope = $fractalManager->createData($resource, $dunglasResource->getShortName()); if ($defaultIncludes === false) { $transformer->setDefaultIncludes([]); } $transformer->setCurrentScope($rootScope)->setEmbed($dunglasResource->getShortName()); return $rootScope->toArray(); }
/** * {@inheritdoc} * * @return Request[] */ public function generate(ResourceInterface $resource = null) { /** @var OperationInterface[] $operations */ $operations = array_merge($resource->getCollectionOperations(), $resource->getItemOperations()); $requests = []; foreach ($operations as $operation) { $route = $operation->getRoute(); foreach ($route->getMethods() as $method) { $request = new Request(); $request->setResource($resource); $request->setId((string) Uuid::uuid4()); $request->setUrl($this->baseUrl . $route->getPath()); $request->setMethod($method); if (isset($operation->getContext()['hydra:title'])) { $request->setName($operation->getContext()['hydra:title']); } $this->requestParser->parse($request); $requests[] = $request; } } return $requests; }
public function testSupportsResultPaginationDisabled() { /** @var ObjectProphecy|Request $requestMock */ $requestMock = $this->prophesize('Symfony\\Component\\HttpFoundation\\Request'); /* @see PaginationExtension::supportsResult */ $this->requestStackMock->getCurrentRequest()->willReturn($requestMock->reveal())->shouldBeCalledTimes(1); /* @see PaginationExtension::isPaginationEnabled */ $this->resourceMock->getEnablePaginationParameter()->willReturn('enablePagination')->shouldBeCalledTimes(1); $requestMock->get('enablePagination')->willReturn('true')->shouldBeCalledTimes(1); $this->resourceMock->isClientAllowedToEnablePagination()->willReturn(false)->shouldBeCalledTimes(1); $this->resourceMock->isPaginationEnabledByDefault()->willReturn(false)->shouldBeCalledTimes(1); $extension = new PaginationExtension($this->managerRegistryMock->reveal(), $this->requestStackMock->reveal()); $this->assertFalse($extension->supportsResult($this->resourceMock->reveal())); }
/** * @param $data * @param $dataToSerialize */ protected function setEmbed($data, $dataToSerialize) { if (isset($data['tags']['embed']) && isset($data['tags']['collection'])) { $filter = new EmbedFilter($this->managerRegistry, $this->propertyAccessor); $item = $dataToSerialize->getIterator()->current(); if (null === ($params = $this->apiResource->getRouteKeyParams($item))) { $params['id'] = $this->propertyAccessor->getValue($item, 'id'); } $params['embed'] = $this->apiResource->getShortName(); $filter->setParameters($params); $filter->setRouteName($data['routeName']); $this->apiResource->addFilter($filter); } }
/** * Gets class metadata for the given resource. * * @param ResourceInterface $resource * * @return ClassMetadata */ private function getClassMetadata(ResourceInterface $resource) { $entityClass = $resource->getEntityClass(); return $this->managerRegistry->getManagerForClass($entityClass)->getClassMetadata($entityClass); }
/** * Gets the number of items per page to display. * * @param ResourceInterface $resource * @param Request $request * * @return float */ private function getItemsPerPage(ResourceInterface $resource, Request $request) { if ($resource->isClientAllowedToChangeItemsPerPage() && ($itemsPerPage = $request->get($resource->getItemsPerPageParameter()))) { return (double) $itemsPerPage; } return $resource->getItemsPerPageByDefault(); }
/** * Gets metadata for the given resource with the current context. * * Fallback to the resource own groups if no context is provided. * * @param ResourceInterface $resource * @param array $context * * @return ClassMetadataInterface */ private function getMetadata(ResourceInterface $resource, array $context) { return $this->apiClassMetadataFactory->getMetadataFor($resource->getEntityClass(), isset($context['json_ld_normalization_groups']) ? $context['json_ld_normalization_groups'] : $resource->getNormalizationGroups(), isset($context['json_ld_denormalization_groups']) ? $context['json_ld_denormalization_groups'] : $resource->getDenormalizationGroups(), isset($context['json_ld_validation_groups']) ? $context['json_ld_validation_groups'] : $resource->getValidationGroups()); }
/** * Bootstrap relation context. * * @param ResourceInterface $resource * @param string $class * * @return array */ public function bootstrapRelation(ResourceInterface $resource, $class) { return ['resource' => $this->resourceCollection->getResourceForEntity($class), 'json_ld_has_context' => true, 'json_ld_normalization_groups' => $resource->getNormalizationGroups(), 'json_ld_denormalization_groups' => $resource->getDenormalizationGroups(), 'json_ld_validation_groups' => $resource->getValidationGroups()]; }
/** * Creates operation. * * @param ResourceInterface $resource * @param bool $collection * @param string|array $methods * @param string|null $path * @param null $controller * @param null $routeName * @param array $context * * @return Operation */ private function createOperation(ResourceInterface $resource, $collection, $methods, $path = null, $controller = null, $routeName = null, array $context = []) { $shortName = $resource->getShortName(); if (!isset(self::$inflectorCache[$shortName])) { self::$inflectorCache[$shortName] = Inflector::pluralize(Inflector::tableize($shortName)); } // Populate path if (!$path) { $path = '/' . self::$inflectorCache[$shortName]; if (!$collection) { $path .= '/{id}'; } } // Guess default method if (is_array($methods)) { $defaultMethod = $methods[0]; } else { $defaultMethod = $methods; } // Populate controller if (!$controller) { $defaultAction = strtolower($defaultMethod); if ($collection) { $defaultAction = 'c' . $defaultAction; } $controller = self::DEFAULT_CONTROLLER . ':' . $defaultAction; // Populate route name if (!$routeName) { $routeName = self::$inflectorCache[$shortName] . '_' . $defaultAction; } } $requirements = []; if (strpos($path, '{id}')) { $requirements['id'] = '\\d+'; } if (strpos($path, '{embed}')) { try { $embeds = $this->transformerHelper->getAvailableIncludes($shortName); $requirements['embed'] = implode('|', $embeds); } catch (\Exception $ex) { //commande sfroute symfony } } // $requirements ['"context.getApiVersion() === '".$apiVersion."'"'] return new Operation(new Route($path, ['_controller' => $controller, '_resource' => $shortName], $requirements, [], '', [], $methods), self::ROUTE_NAME_PREFIX . $resource->getVersion() . '_' . $routeName, $context); }
/** * Normalizes data using the Symfony Serializer. * * @param ResourceInterface $resource * @param array|object $data * @param int $status * @param array $headers * @param array $additionalContext * * @return Response */ protected function getSuccessResponse(ResourceInterface $resource, $data, $status = 200, array $headers = [], array $additionalContext = []) { return new Response($this->get('serializer')->normalize($data, 'json-ld', $resource->getNormalizationContext() + $additionalContext), $status, $headers); }
/** * Gets the context URI for the given resource. * * @param ResourceInterface $resource * * @return string */ public function getContextUri(ResourceInterface $resource) { return $this->router->generate('api_jsonld_context', ['shortName' => $resource->getShortName()]); }
/** * @param ResourceInterface $resource * * @return AttributeMetadataInterface */ private function getIdentifierFromResource(ResourceInterface $resource) { $classMetadata = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass(), $resource->getNormalizationGroups(), $resource->getDenormalizationGroups(), $resource->getValidationGroups()); return $classMetadata->getIdentifier(); }
/** * {@inheritdoc} */ public function supports(ResourceInterface $resource) { return null !== $this->managerRegistry->getManagerForClass($resource->getEntityClass()); }
/** * created querybuilder * * @param ResourceInterface $resource * @param Request $request * @return mixed */ public function getQueryBuilderForCollection(ResourceInterface $resource, Request $request) { $entityClass = $resource->getEntityClass(); $manager = $this->managerRegistry->getManagerForClass($resource->getEntityClass()); $repository = $manager->getRepository($entityClass); $page = (int) $request->get($this->pageParameter, 1); $itemsPerPage = $this->getItemPerPage($request); $queryBuilder = $this->getQB($request, $repository, $page, $itemsPerPage); foreach ($resource->getFilters() as $filter) { if ($filter instanceof FilterInterface) { $filter->apply($resource, $queryBuilder, $request); } } return $queryBuilder; }
/** * Gets and populates if applicable a Hydra operation. * * @param ResourceInterface $resource * @param OperationInterface $operation * @param string $prefixedShortName * @param bool $collection * * @return array */ private function getHydraOperation(ResourceInterface $resource, OperationInterface $operation, $prefixedShortName, $collection) { $method = $operation->getRoute()->getMethods(); if (is_array($method)) { $method = $method[0]; } $hydraOperation = $operation->getContext(); switch ($method) { case 'GET': if ($collection) { if (!isset($hydraOperation['hydra:title'])) { $hydraOperation['hydra:title'] = sprintf('Retrieves the collection of %s resources.', $resource->getShortName()); } if (!isset($hydraOperation['returns'])) { $hydraOperation['returns'] = 'hydra:PagedCollection'; } } else { if (!isset($hydraOperation['hydra:title'])) { $hydraOperation['hydra:title'] = sprintf('Retrieves %s resource.', $resource->getShortName()); } } break; case 'POST': if (!isset($hydraOperation['@type'])) { $hydraOperation['@type'] = 'hydra:CreateResourceOperation'; } if (!isset($hydraOperation['hydra:title'])) { $hydraOperation['hydra:title'] = sprintf('Creates a %s resource.', $resource->getShortName()); } break; case 'PUT': if (!isset($hydraOperation['@type'])) { $hydraOperation['@type'] = 'hydra:ReplaceResourceOperation'; } if (!isset($hydraOperation['hydra:title'])) { $hydraOperation['hydra:title'] = sprintf('Replaces the %s resource.', $resource->getShortName()); } break; case 'DELETE': if (!isset($hydraOperation['hydra:title'])) { $hydraOperation['hydra:title'] = sprintf('Deletes the %s resource.', $resource->getShortName()); } if (!isset($hydraOperation['returns'])) { $hydraOperation['returns'] = 'owl:Nothing'; } break; } if (!isset($hydraOperation['returns']) && ('GET' === $method && !$collection || 'POST' === $method || 'PUT' === $method)) { $hydraOperation['returns'] = $prefixedShortName; } if (!isset($hydraOperation['expects']) && ('POST' === $method || 'PUT' === $method)) { $hydraOperation['expects'] = $prefixedShortName; } if (!isset($hydraOperation['@type'])) { $hydraOperation['@type'] = 'hydra:Operation'; } if (!isset($hydraOperation['hydra:method'])) { $hydraOperation['hydra:method'] = $method; } if (!isset($hydraOperation['rdfs:label']) && isset($hydraOperation['hydra:title'])) { $hydraOperation['rdfs:label'] = $hydraOperation['hydra:title']; } ksort($hydraOperation); return $hydraOperation; }
/** * Denormalizes a relation. * * @param ResourceInterface $currentResource * @param AttributeMetadata $attributeMetadata * @param $class * @param $value * * @return object * @throws InvalidArgumentException */ private function denormalizeRelation(ResourceInterface $currentResource, AttributeMetadata $attributeMetadata, $class, $value) { if ('Datetime' === $class) { $dateTimeNormalizer = new DateTimeNormalizer(); return $dateTimeNormalizer->denormalize($value, $class ?: null, self::FORMAT); } $attributeName = $attributeMetadata->getName(); // // Always allow IRI to be compliant with the Hydra spec // if (is_string($value)) { // $item = $this->dataProvider->getItemFromIri($value); // if (null === $item) { // throw new InvalidArgumentException(sprintf( // 'IRI not supported (found "%s" in "%s" of "%s")', // $value, // $attributeName, // $currentResource->getEntityClass() // )); // } // return $item; // } if (!$this->resourceCollection->getResourceForEntity($class)) { $shortname = ucfirst(Inflector::singularize($attributeName)); if (!$this->resourceCollection->getResourceForShortName($shortname)) { throw new InvalidArgumentException(sprintf('Type not supported (found "%s" in attribute "%s" of "%s")', $class, $attributeName, $currentResource->getEntityClass())); } else { $resource = $this->resourceCollection->getResourceForShortName($shortname); $context = $this->contextBuilder->bootstrapRelation($resource, $resource->getEntityClass()); } } else { $context = $this->contextBuilder->bootstrapRelation($currentResource, $class); } if (!$attributeMetadata->isDenormalizationLink()) { $object = $this->denormalize(json_encode($value), $resource->getEntityClass(), self::FORMAT, $context); //$this->deserializeObjects[] = $object; return $object; } throw new InvalidArgumentException(sprintf('Nested objects for attribute "%s" of "%s" are not enabled. Use serialization groups to change that behavior.', $attributeName, $currentResource->getEntityClass())); }