Skip to content

Commit 5be041c

Browse files
author
Aymeric Ratinaud
committed
JobDataProvider
1 parent 29ac71e commit 5be041c

File tree

8 files changed

+229
-3
lines changed

8 files changed

+229
-3
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Inspired by https://github.com/api-platform/demo
1212
- [Sixth example use FurnitureDataProvider (collectionDataProvider)] https://github.com/aratinau/api-platform-pagination#sixth-example-use-FurnitureDataProvider-(collectionDataProvider)
1313
- [Seventh example use QueryBuilder in subresource]
1414
- [Eight example use QueryBuilder in subresource] https://github.com/aratinau/api-platform-pagination#eight-example-use-QueryBuilder-in-subresource
15+
- [Ninth use custom subresource with provider (without subresourceDataProvider)] https://github.com/aratinau/api-platform-pagination#ninth-example---custom-subresource-with-provider-(without-subresourceDataProvider)
1516

1617

1718
## First Example use raw data from a csv file
@@ -98,7 +99,9 @@ Basic example showing how use and configure CollectionDataProvider
9899

99100
## Seventh example : simple DataProvider using subresourceDataProvider
100101

101-
CommentSubresourceDataProvider show how use the standard behaviour
102+
CommentSubresourceDataProvider show how use the standard behaviour
103+
104+
### Usage
102105

103106
`api/movies/{id}/comments`
104107

@@ -110,6 +113,16 @@ DiscussionSubresourceDataProvider show how use QueryBuilder and order by DESC th
110113

111114
`api/discussions/{id}/messages?page=1`
112115

116+
## Ninth example - custom subresource with provider (without subresourceDataProvider)
117+
118+
With JobDataProvider and path `jobs/{id}/employees` return employees from id's job
119+
120+
[ ] TODO Pagination
121+
122+
### Usage
123+
124+
`api/jobs/{id}/employees`
125+
113126
## Install
114127

115128
composer install

config/services.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@ services:
3737
App\DataProvider\FurnitureDataProvider:
3838
bind:
3939
$collectionDataProvider: '@api_platform.doctrine.orm.default.collection_data_provider'
40+
41+
App\DataProvider\JobDataProvider:
42+
bind:
43+
$itemDataProvider: '@api_platform.doctrine.orm.default.item_data_provider'

fixtures/employee.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
App\Entity\Employee:
2+
employee_{1..1000}:
3+
author: <name()>

fixtures/job.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
App\Entity\Job:
2-
job_{1..1000}:
2+
job_{1..100}:
33
name: <word(10, 700)>
44
isPublished: '<numberBetween(0, 1)>'
5+
employees: '<numberBetween(100, 200)>x @employee*'

src/DataProvider/JobDataProvider.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\DataProvider;
6+
7+
use ApiPlatform\Core\DataProvider\DenormalizedIdentifiersAwareItemDataProviderInterface;
8+
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
9+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
10+
use App\Entity\Job;
11+
12+
final class JobDataProvider implements RestrictedDataProviderInterface, DenormalizedIdentifiersAwareItemDataProviderInterface
13+
{
14+
private $itemDataProvider;
15+
16+
public function __construct(ItemDataProviderInterface $itemDataProvider)
17+
{
18+
$this->itemDataProvider = $itemDataProvider;
19+
}
20+
21+
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
22+
{
23+
return
24+
$resourceClass === Job::class &&
25+
$operationName === "custom-subresource-job-employees"
26+
;
27+
}
28+
29+
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
30+
{
31+
$itemDataProvider = $this->itemDataProvider->getItem($resourceClass, $id, $operationName, $context);
32+
33+
return $itemDataProvider->getEmployees()->getValues();
34+
}
35+
}

src/Entity/Employee.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace App\Entity;
4+
5+
use ApiPlatform\Core\Annotation\ApiResource;
6+
use App\Repository\EmployeeRepository;
7+
use Doctrine\ORM\Mapping as ORM;
8+
use Symfony\Component\Serializer\Annotation\Groups;
9+
10+
/**
11+
* @ApiResource()
12+
* @ORM\Entity(repositoryClass=EmployeeRepository::class)
13+
*/
14+
class Employee
15+
{
16+
/**
17+
* @ORM\Id
18+
* @ORM\GeneratedValue
19+
* @ORM\Column(type="integer")
20+
* @Groups({"normalization-custom-subresource-job-employees"})
21+
*/
22+
private $id;
23+
24+
/**
25+
* @ORM\Column(type="string", length=255)
26+
* @Groups({"normalization-custom-subresource-job-employees"})
27+
*/
28+
private $author;
29+
30+
/**
31+
* @ORM\ManyToOne(targetEntity=Job::class, inversedBy="employees")
32+
* @ORM\JoinColumn(nullable=false)
33+
*/
34+
private $job;
35+
36+
public function getId(): ?int
37+
{
38+
return $this->id;
39+
}
40+
41+
public function getAuthor(): ?string
42+
{
43+
return $this->author;
44+
}
45+
46+
public function setAuthor(string $author): self
47+
{
48+
$this->author = $author;
49+
50+
return $this;
51+
}
52+
53+
public function getJob(): ?Job
54+
{
55+
return $this->job;
56+
}
57+
58+
public function setJob(?Job $job): self
59+
{
60+
$this->job = $job;
61+
62+
return $this;
63+
}
64+
}

src/Entity/Job.php

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@
44

55
use ApiPlatform\Core\Annotation\ApiResource;
66
use App\Repository\JobRepository;
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\Common\Collections\Collection;
79
use Doctrine\ORM\Mapping as ORM;
10+
use Symfony\Component\Serializer\Annotation\Groups;
811

912
/**
1013
* @ApiResource(
11-
* attributes={"pagination_enabled"=true}
14+
* attributes={"pagination_enabled"=true},
15+
* itemOperations={
16+
* "get",
17+
* "custom-subresource-job-employees"={
18+
* "method"="GET",
19+
* "deserialize"=false,
20+
* "path"="/jobs/{id}/employees",
21+
* "normalization_context"={"groups" = "normalization-custom-subresource-job-employees"}
22+
* }
23+
* }
1224
* )
1325
* @ORM\Entity(repositoryClass=JobRepository::class)
1426
*/
@@ -18,19 +30,33 @@ class Job
1830
* @ORM\Id
1931
* @ORM\GeneratedValue
2032
* @ORM\Column(type="integer")
33+
* @Groups({"normalization-custom-subresource-job-employees"})
2134
*/
2235
private $id;
2336

2437
/**
2538
* @ORM\Column(type="string", length=255)
39+
* @Groups({"normalization-custom-subresource-job-employees"})
2640
*/
2741
private $name;
2842

2943
/**
3044
* @ORM\Column(type="boolean")
45+
* @Groups({"normalization-custom-subresource-job-employees"})
3146
*/
3247
private $isPublished;
3348

49+
/**
50+
* @ORM\OneToMany(targetEntity=Employee::class, mappedBy="job")
51+
* @Groups({"normalization-custom-subresource-job-employees"})
52+
*/
53+
private $employees;
54+
55+
public function __construct()
56+
{
57+
$this->employees = new ArrayCollection();
58+
}
59+
3460
public function getId(): ?int
3561
{
3662
return $this->id;
@@ -58,4 +84,34 @@ public function setIsPublished(bool $isPublished): self
5884

5985
return $this;
6086
}
87+
88+
/**
89+
* @return Collection|Employee[]
90+
*/
91+
public function getEmployees(): Collection
92+
{
93+
return $this->employees;
94+
}
95+
96+
public function addEmployee(Employee $employee): self
97+
{
98+
if (!$this->employees->contains($employee)) {
99+
$this->employees[] = $employee;
100+
$employee->setJob($this);
101+
}
102+
103+
return $this;
104+
}
105+
106+
public function removeEmployee(Employee $employee): self
107+
{
108+
if ($this->employees->removeElement($employee)) {
109+
// set the owning side to null (unless already changed)
110+
if ($employee->getJob() === $this) {
111+
$employee->setJob(null);
112+
}
113+
}
114+
115+
return $this;
116+
}
61117
}

src/Repository/EmployeeRepository.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace App\Repository;
4+
5+
use App\Entity\Employee;
6+
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
7+
use Doctrine\Persistence\ManagerRegistry;
8+
9+
/**
10+
* @method Employee|null find($id, $lockMode = null, $lockVersion = null)
11+
* @method Employee|null findOneBy(array $criteria, array $orderBy = null)
12+
* @method Employee[] findAll()
13+
* @method Employee[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
14+
*/
15+
class EmployeeRepository extends ServiceEntityRepository
16+
{
17+
public function __construct(ManagerRegistry $registry)
18+
{
19+
parent::__construct($registry, Employee::class);
20+
}
21+
22+
// /**
23+
// * @return Employee[] Returns an array of Employee objects
24+
// */
25+
/*
26+
public function findByExampleField($value)
27+
{
28+
return $this->createQueryBuilder('e')
29+
->andWhere('e.exampleField = :val')
30+
->setParameter('val', $value)
31+
->orderBy('e.id', 'ASC')
32+
->setMaxResults(10)
33+
->getQuery()
34+
->getResult()
35+
;
36+
}
37+
*/
38+
39+
/*
40+
public function findOneBySomeField($value): ?Employee
41+
{
42+
return $this->createQueryBuilder('e')
43+
->andWhere('e.exampleField = :val')
44+
->setParameter('val', $value)
45+
->getQuery()
46+
->getOneOrNullResult()
47+
;
48+
}
49+
*/
50+
}

0 commit comments

Comments
 (0)