getUser(); $query = new ProjectQuery(); $query->setCurrentUser($user); $order = $paramFetcher->get('order'); if (\is_string($order) && $order !== '') { $query->setOrder($order); } $orderBy = $paramFetcher->get('orderBy'); if (\is_string($orderBy) && $orderBy !== '') { $query->setOrderBy($orderBy); } /** @var array $customers */ $customers = $paramFetcher->get('customers'); $customer = $paramFetcher->get('customer'); if (\is_string($customer) && $customer !== '') { $customers[] = $customer; } foreach (array_unique($customers) as $customerId) { $customer = $customerRepository->find($customerId); if ($customer === null) { throw $this->createNotFoundException('Unknown customer: ' . $customerId); } $query->addCustomer($customer); } $visible = $paramFetcher->get('visible'); if (\is_string($visible) && $visible !== '') { $query->setVisibility((int) $visible); } $globalActivities = $paramFetcher->get('globalActivities'); if ($globalActivities !== null) { $query->setGlobalActivities((bool) $globalActivities); } $ignoreDates = false; if (null !== ($ign = $paramFetcher->get('ignoreDates'))) { $ignoreDates = $ign === 1 || $ign === '1'; } if (!$ignoreDates) { $factory = $this->getDateTimeFactory(); $now = $factory->createDateTime(); $begin = $paramFetcher->get('start'); $end = $paramFetcher->get('end'); if (\is_string($begin) && $begin !== '') { $query->setProjectStart($factory->createDateTime($begin)); } if (\is_string($end) && $end !== '') { $query->setProjectEnd($factory->createDateTime($end)); } if ($query->getProjectStart() === null && $query->getProjectEnd() === null) { $query->setProjectStart($now); $query->setProjectEnd($now); } } $term = $paramFetcher->get('term'); if (\is_string($term) && $term !== '') { $query->setSearchTerm(new SearchTerm($term)); } $data = $this->repository->getProjectsForQuery($query); $view = new View($data, 200); $view->getContext()->setGroups(self::GROUPS_COLLECTION); return $this->viewHandler->handle($view); } /** * Returns one project */ #[OA\Response(response: 200, description: 'Returns one project entity', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))] #[Rest\Get(path: '/{id}', name: 'get_project', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] public function getAction(Project $project): Response { $view = new View($project, 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Creates a new project */ #[OA\Post(description: 'Creates a new project and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))] #[Rest\Post(path: '', name: 'post_project')] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] public function postAction(Request $request): Response { if (!$this->isGranted('create_project')) { throw $this->createAccessDeniedException('User cannot create projects'); } $project = $this->projectService->createNewProject(); $form = $this->createForm(ProjectApiEditForm::class, $project, [ 'timezone' => $this->getDateTimeFactory()->getTimezone()->getName(), 'date_format' => self::DATE_ONLY_FORMAT, 'include_budget' => $this->isGranted('budget', $project), 'include_time' => $this->isGranted('time', $project), ]); $form->submit($request->request->all()); if ($form->isValid()) { $this->projectService->saveNewProject($project); $view = new View($project, 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } $view = new View($form); $view->getContext()->setGroups(self::GROUPS_FORM); return $this->viewHandler->handle($view); } /** * Update an existing project */ #[IsGranted('edit', 'project')] #[OA\Patch(description: 'Update an existing project, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to update', required: true)] #[Rest\Patch(path: '/{id}', name: 'patch_project', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] public function patchAction(Request $request, Project $project): Response { $event = new ProjectMetaDefinitionEvent($project); $this->dispatcher->dispatch($event); $form = $this->createForm(ProjectApiEditForm::class, $project, [ 'timezone' => $this->getDateTimeFactory()->getTimezone()->getName(), 'date_format' => self::DATE_FORMAT, 'include_budget' => $this->isGranted('budget', $project), 'include_time' => $this->isGranted('time', $project), ]); $form->setData($project); $form->submit($request->request->all(), false); if (false === $form->isValid()) { $view = new View($form, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_FORM); return $this->viewHandler->handle($view); } $this->projectService->updateProject($project); $view = new View($project, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Sets the value of a meta-field for an existing project */ #[IsGranted('edit', 'project')] #[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Project record ID to set the meta-field value for', required: true)] #[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')] #[Rest\RequestParam(name: 'value', strict: true, nullable: false, description: 'The meta-field value')] public function metaAction(Project $project, ParamFetcherInterface $paramFetcher): Response { $event = new ProjectMetaDefinitionEvent($project); $this->dispatcher->dispatch($event); $name = $paramFetcher->get('name'); $value = $paramFetcher->get('value'); if (null === ($meta = $project->getMetaField($name))) { throw $this->createNotFoundException('Unknown meta-field requested'); } $meta->setValue($value); $this->projectService->updateProject($project); $view = new View($project, 200); $view->getContext()->setGroups(self::GROUPS_ENTITY); return $this->viewHandler->handle($view); } /** * Returns a collection of all rates for one project */ #[IsGranted('edit', 'project')] #[OA\Response(response: 200, description: 'Returns a collection of project rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectRate')))] #[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rates will be returned', required: true)] #[Rest\Get(path: '/{id}/rates', name: 'get_project_rates', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] public function getRatesAction(Project $project): Response { $rates = $this->projectRateRepository->getRatesForProject($project); $view = new View($rates, 200); $view->getContext()->setGroups(self::GROUPS_RATE); return $this->viewHandler->handle($view); } /** * Deletes one rate for a project */ #[IsGranted('edit', 'project')] #[OA\Delete(responses: [new OA\Response(response: 204, description: 'Returns no content: 204 on successful delete')])] #[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rate will be removed', required: true)] #[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] #[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_project_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])] public function deleteRateAction(Project $project, #[MapEntity(mapping: ['rateId' => 'id'])] ProjectRate $rate): Response { if ($rate->getProject() !== $project) { throw $this->createNotFoundException(); } $this->projectRateRepository->deleteRate($rate); $view = new View(null, Response::HTTP_NO_CONTENT); return $this->viewHandler->handle($view); } /** * Adds a new rate to a project */ #[IsGranted('edit', 'project')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ProjectRate'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The project to add the rate for', required: true)] #[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectRateForm'))] #[Rest\Post(path: '/{id}/rates', name: 'post_project_rate', requirements: ['id' => '\d+'])] #[ApiSecurity(name: 'apiUser')] #[ApiSecurity(name: 'apiToken')] public function postRateAction(Project $project, Request $request): Response { $rate = new ProjectRate(); $rate->setProject($project); $form = $this->createForm(ProjectRateApiForm::class, $rate, [ 'method' => 'POST', ]); $form->setData($rate); $form->submit($request->request->all(), false); if (false === $form->isValid()) { $view = new View($form, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_RATE); return $this->viewHandler->handle($view); } $this->projectRateRepository->saveRate($rate); $view = new View($rate, Response::HTTP_OK); $view->getContext()->setGroups(self::GROUPS_RATE); return $this->viewHandler->handle($view); } }