I'm new to php, doctrine and symfony. Please feel free to give me suggestions for improvement. Sry if my English isn't accurate.
What do I want to achieve?
I want to:
- filter a collection (
Protocols) by a dynamic getter (getTimeTrackerState) of my (Protocol) Entity model. - see the filter in the graphql playground within the collection
protocols. - be able to execute a query with a filter value.
My initial situation
The Entity Code: Protocol.php
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use Doctrine\ORM\Mapping as ORM;
/**
* @ApiResource()
* @Vich\Uploadable()
* @ORM\Entity(repositoryClass=ProtocolRepository::class)
*
* @ApiFilter(DateFilter::class, properties={"dueDate"})
* @ApiFilter(SearchFilter::class, properties={"timeTrackerState": "exact", "state": "exact"})
*
*/
class Protocol
{
/**
* @var string
*
* @ORM\Id()
* @ORM\GeneratedValue(strategy="UUID")
* @ORM\Column(type="guid")
*
* @Assert\Uuid()
*/
private $id;
// some other fields
// /**
// * @var string
// *
// * @ORM\Column(type="string")
// */
// public $timeTrackerState;
public function getTimeTrackerState(): string
{
if ($this->getDaysUntilExeeded() <= 0) {
return Protocol::TIME_TRACKER_EXEEDED;
} elseif ($this->getDaysUntilUpcoming() <= 0) {
return Protocol::TIME_TRACKER_UPCOMING;
} else {
return Protocol::TIME_TRACKER_NOT_UPCOMING;
}
}
// not setter!
}
graphql query:
query GetProtocols {
protocols(timeTrackerState: "UPCOMING") {
pageInfo {
endCursor
hasNextPage
}
totalCount
edges {
cursor
node {
...ProtocolCore
state
timeTrackerState
... other stuff
}
}
}
}
loaded graphql schema docs (playground):
What is the problem?
The filter is not available in graphql (see loaded graphql schema docs), as long as there is no field declared, which is annotated with (@ORM\Column(type="string")). If I declare this field named timeTrackerState , then this field appears in the loaded graphql schema docs, but I also need to store it in the database, what isn't what I want. Queries with a applied filter value (i.e. timeTrackerState: "UPCOMING") will verify against the database and not against the dynamic getter getTimeTrackerState() of my entity class. I think this behaviour is intended of doctrine.
Maybe I'm missing some basic functionality, or I'm completely off with my plan and should reconsider the structure.
I also thought about filtering it in the frontend, but then I need to fetch many unnecessary entries (protocol) with states I'm not interested in.
What I tried so far
As described above, I used a
@ORM\Column(type="string")field to write the field into the database and query it from there. The problem here is that I don't know how to keep it up to date.I wrote a custom-resolver which nearly does what I want, BUT then I end up having two queries for the same resource and they only differ in their arguments, which I want to have together. I don't know how to merge my custom Resolver with the already provided Resolver used by
protocols.ProtocolCollecctionResolver.php:use ApiPlatform\Core\GraphQl\Resolver\QueryCollectionResolverInterface; use App\Entity\Protocol; final class ProtocolCollectionResolver implements QueryCollectionResolverInterface { /** * @param iterable<Protocol> $collection * * @return iterable<Protocol> */ public function __invoke(iterable $collection, array $context): iterable { ... return $collection }usage of Resolver in Entity
Protocol.php:/** * @ApiResource( * graphql={ * "item_query", * "collection_query", * "delete", * "update", * "create", * * "collectionQuery"={ * "collection_query"=ProtocolCollectionResolver::class, * "args"={ * "timeTrackerState"={ * "type"="String!", * "description"="The time state of the protocol" * } * } * }, * } * ) * * @Vich\Uploadable() * @ORM\Entity(repositoryClass=ProtocolRepository::class) * * @ApiFilter(DateFilter::class, properties={"dueDate"}) * @ApiFilter(SearchFilter::class, properties={"timeTrackerState": "exact", "state": "exact"}) */ class Protocol {}loaded graphql schema docs (playground):
Thank you in advice!

