# Subresources
A Subresource is another way of declaring a resource that usually involves a more complex URI.
In API Platform you can declare as many `ApiResource` as you want on a PHP class
creating Subresources.
Subresources work well by implementing your own state [providers](./state-providers.md)
or [processors](./state-processors.md). In API Platform, we provide functional Doctrine and Eloquent layers for
subresources, as long as the correct configuration for URI variables is added.
## URI Variables Configuration
URI Variables are configured via the `uriVariables` node on an `ApiResource`. It's an array indexed by the variables
present in your URI, `/companies/{companyId}/employees/{id}` has two URI variables `companyId` and `id`.
For each of these, we need to create a `Link` between the previous and the next node, in this example the link between a Company and an Employee.
If you're using the Doctrine or the Eloquent implementation, queries are automatically built using the provided links.
### Answer to a Question
> [!NOTE]
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
For this example we have two classes, a Question and an Answer. We want to find the Answer to
the Question about the Universe using the following URI: `/question/42/answer`.
Let's start by defining the resources:
```php
id;
}
// ...
}
// api/src/Entity/Question.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ApiResource]
class Question
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
private ?int $id = null;
#[ORM\Column(type: 'text')]
public string $content;
#[ORM\OneToOne]
#[ORM\JoinColumn(referencedColumnName: 'id', unique: true)]
public Answer $answer;
public function getId(): ?int
{
return $this->id;
}
// ...
}
```
```yaml
# The YAML syntax is only supported for Symfony
# api/config/api_platform/resources.yaml
resources:
App\Entity\Answer: ~
App\Entity\Question: ~
```
```xml
```
Now to create a new way of retrieving an Answer we will declare another resource on the `Answer` class.
To make things work, API Platform needs information about how to retrieve the `Answer` belonging to
the `Question`, this is done by configuring the `uriVariables`:
```php
new Link(
fromClass: Question::class,
fromProperty: 'answer'
)
],
operations: [new Get()]
)]
class Answer
{
// ...
}
```
```yaml
# The YAML syntax is only supported for Symfony
# api/config/api_platform/resources.yaml
resources:
App\Entity\Answer:
uriTemplate: /questions/{id}/answer
uriVariables:
id:
fromClass: App\Entity\Question
fromProperty: answer
operations:
ApiPlatform\Metadata\Get: ~
App\Entity\Question: ~
```
```xml
```
In this example, we instructed API Platform that the `Answer` we retrieve comes **from** the **class** `Question`
**from** the **property** `answer` of that class.
URI Variables are defined using Links (`ApiPlatform\Metadata\Link`). A `Link` can be binded either from or to a class and a property.
If we had a `relatedQuestions` property on the `Answer` we could retrieve the collection of related questions via the following definition:
```php
#[ApiResource(
uriTemplate: '/answers/{id}/related_questions.{_format}',
uriVariables: [
'id' => new Link(fromClass: Answer::class, fromProperty: 'relatedQuestions')
],
operations: [new GetCollection()]
)]
```
```yaml
#The YAML syntax is only supported for Symfony
# api/config/api_platform/resources.yaml
resources:
App\Entity\Question:
uriTemplate: /answers/{id}/related_questions.{_format}
uriVariables:
id:
fromClass: App\Entity\Answer
fromProperty: relatedQuestions
operations:
ApiPlatform\Metadata\GetCollection: ~
```
```xml
```
### Company Employee's
> [!NOTE]
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
Note that in this example, we declared an association using Doctrine only between Employee and Company using a ManyToOne. There is no inverse association hence the use of `toProperty` in the URI Variables definition.
The following declares a few subresources: - `/companies/{companyId}/employees/{id}` - get an employee belonging to a company - `/companies/{companyId}/employees` - get the company employee's
```php
new Link(fromClass: Company::class, toProperty: 'company'),
'id' => new Link(fromClass: Employee::class),
],
operations: [ new Get() ]
)]
#[ApiResource(
uriTemplate: '/companies/{companyId}/employees',
uriVariables: [
'companyId' => new Link(fromClass: Company::class, toProperty: 'company'),
],
operations: [ new GetCollection() ]
)]
class Employee
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
public ?int $id;
#[ORM\Column]
public string $name;
#[ORM\ManyToOne(targetEntity: Company::class)]
public ?Company $company;
public function getId()
{
return $this->id;
}
}
```
Now let's add the Company class:
```php
new Link(fromClass: Employee::class, fromProperty: 'company'),
],
operations: [
new Get()
]
)]
class Company {
// ...
}
```
## Security
> [!WARNING]
> This is not yet available with Laravel, you're welcome to contribute [on GitHub](https://github.com/api-platform/core)
In order to use Symfony's built-in security system on subresources the security option of the `Link` attribute can be used.
To restrict the access to a subresource based on the parent object simply use the Symfony expression language as you would do normally, with the exception that the name defined in `toProperty` or `fromProperty` is used to access the object.
Alternatively you can also use the `securityObjectName` to set a custom name.
```php
new Link(fromClass: Employee::class, toProperty: 'company', security: "is_granted(some_voter, company)"),
],
operations: [
new Get()
]
)]
class Company {
// ...
}
```
This is currently an experimental feature disabled by default. To enable it please set `enable_link_security` to true:
```yaml
# api/config/packages/api_platform.yaml
api_platform:
enable_link_security: true
```