Skip to content

Commit 982fced

Browse files
emodricpspanja
authored andcommitted
Add support for fetching data via queries and relations with sudo
1 parent c196af6 commit 982fced

14 files changed

Lines changed: 386 additions & 14 deletions

File tree

bundle/QueryType/QueryExecutor.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
99
use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchResult;
1010
use Ibexa\Core\QueryType\QueryTypeRegistry;
11+
use Ibexa\Contracts\Core\Repository\Repository;
1112
use Netgen\IbexaSearchExtra\Core\Pagination\Pagerfanta\BaseAdapter;
1213
use Netgen\IbexaSiteApi\API\FilterService;
1314
use Netgen\IbexaSiteApi\API\FindService;
1415
use Netgen\IbexaSiteApi\Core\Site\Pagination\Pagerfanta\FilterAdapter;
1516
use Netgen\IbexaSiteApi\Core\Site\Pagination\Pagerfanta\FindAdapter;
17+
use Netgen\IbexaSiteApi\Core\Site\Pagination\Pagerfanta\SudoFilterAdapter;
18+
use Netgen\IbexaSiteApi\Core\Site\Pagination\Pagerfanta\SudoFindAdapter;
1619
use Pagerfanta\Pagerfanta;
1720

1821
/**
@@ -26,6 +29,7 @@ public function __construct(
2629
private readonly QueryTypeRegistry $queryTypeRegistry,
2730
private readonly FilterService $filterService,
2831
private readonly FindService $findService,
32+
private readonly Repository $repository,
2933
) {
3034
}
3135

@@ -44,6 +48,21 @@ public function execute(QueryDefinition $queryDefinition): Pagerfanta
4448
return $pager;
4549
}
4650

51+
/**
52+
* Execute the Query with the given $name and return the result using repository sudo.
53+
*/
54+
public function sudoExecute(QueryDefinition $queryDefinition): Pagerfanta
55+
{
56+
$adapter = $this->getSudoPagerAdapter($queryDefinition);
57+
$pager = new Pagerfanta($adapter);
58+
59+
$pager->setNormalizeOutOfRangePages(true);
60+
$pager->setMaxPerPage($queryDefinition->maxPerPage);
61+
$pager->setCurrentPage($queryDefinition->page);
62+
63+
return $pager;
64+
}
65+
4766
/**
4867
* Execute the Query with the given $name and return the result.
4968
*/
@@ -58,6 +77,24 @@ public function executeRaw(QueryDefinition $queryDefinition): SearchResult
5877
return $this->getContentResult($query, $queryDefinition);
5978
}
6079

80+
/**
81+
* Execute the Query with the given $name and return the result using repository sudo.
82+
*/
83+
public function sudoExecuteRaw(QueryDefinition $queryDefinition): SearchResult
84+
{
85+
$query = $this->getQuery($queryDefinition);
86+
87+
if ($query instanceof LocationQuery) {
88+
return $this->repository->sudo(
89+
fn () => $this->getLocationResult($query, $queryDefinition),
90+
);
91+
}
92+
93+
return $this->repository->sudo(
94+
fn () => $this->getContentResult($query, $queryDefinition),
95+
);
96+
}
97+
6198
private function getPagerAdapter(QueryDefinition $queryDefinition): BaseAdapter
6299
{
63100
$query = $this->getQuery($queryDefinition);
@@ -69,6 +106,17 @@ private function getPagerAdapter(QueryDefinition $queryDefinition): BaseAdapter
69106
return new FindAdapter($query, $this->findService);
70107
}
71108

109+
private function getSudoPagerAdapter(QueryDefinition $queryDefinition): BaseAdapter
110+
{
111+
$query = $this->getQuery($queryDefinition);
112+
113+
if ($queryDefinition->useFilter) {
114+
return new SudoFilterAdapter($query, $this->filterService, $this->repository);
115+
}
116+
117+
return new SudoFindAdapter($query, $this->findService, $this->repository);
118+
}
119+
72120
private function getLocationResult(LocationQuery $query, QueryDefinition $queryDefinition): SearchResult
73121
{
74122
if ($queryDefinition->useFilter) {

bundle/Resources/config/services/query_type.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ services:
3131
- '@Ibexa\Core\QueryType\ArrayQueryTypeRegistry'
3232
- '@netgen.ibexa_site_api.filter_service'
3333
- '@netgen.ibexa_site_api.find_service'
34+
- '@ibexa.api.repository'

bundle/Templating/Twig/Extension/QueryExtension.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,21 @@ public function getFunctions(): array
2424
[QueryRuntime::class, 'executeQuery'],
2525
['needs_context' => true],
2626
),
27+
new TwigFunction(
28+
'ng_sudo_query',
29+
[QueryRuntime::class, 'sudoExecuteQuery'],
30+
['needs_context' => true],
31+
),
2732
new TwigFunction(
2833
'ng_raw_query',
2934
[QueryRuntime::class, 'executeRawQuery'],
3035
['needs_context' => true],
3136
),
37+
new TwigFunction(
38+
'ng_sudo_raw_query',
39+
[QueryRuntime::class, 'sudoExecuteRawQuery'],
40+
['needs_context' => true],
41+
),
3242
];
3343
}
3444
}

bundle/Templating/Twig/Extension/QueryRuntime.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,27 @@ public function executeQuery(mixed $context, string $name): Pagerfanta
3131
);
3232
}
3333

34+
public function sudoExecuteQuery(mixed $context, string $name): Pagerfanta
35+
{
36+
return $this->queryExecutor->sudoExecute(
37+
$this->getQueryDefinitionCollection($context)->get($name),
38+
);
39+
}
40+
3441
public function executeRawQuery(mixed $context, string $name): SearchResult
3542
{
3643
return $this->queryExecutor->executeRaw(
3744
$this->getQueryDefinitionCollection($context)->get($name),
3845
);
3946
}
4047

48+
public function sudoExecuteRawQuery(mixed $context, string $name): SearchResult
49+
{
50+
return $this->queryExecutor->sudoExecuteRaw(
51+
$this->getQueryDefinitionCollection($context)->get($name),
52+
);
53+
}
54+
4155
/**
4256
* Returns the QueryDefinitionCollection variable from the given $context.
4357
*

docs/reference/query_types.rst

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -509,18 +509,18 @@ Values that will be provided for evaluation in your custom expression function i
509509
Templating
510510
--------------------------------------------------------------------------------
511511

512-
Configured queries will be available in Twig templates, through ``ng_query`` or ``ng_raw_query``.
512+
Configured queries will be available in Twig templates, through ``ng_query``, ``ng_sudo_query``, ``ng_raw_query`` or ``ng_sudo_raw_query``.
513513
The difference it that the former will return a ``Pagerfanta`` instance, while the latter will
514-
return an instance of ``SearchResult``. That also means ``ng_query`` will use ``max_per_page`` and
515-
``page`` parameters to configure the pager, while ``ng_raw_query`` ignores them and executes the
514+
return an instance of ``SearchResult``. That also means ``ng_query`` and ``ng_sudo_query`` will use ``max_per_page`` and
515+
``page`` parameters to configure the pager, while ``ng_raw_query`` and ``ng_sudo_raw_query`` ignore them and execute the
516516
configured query directly.
517517

518518
.. note::
519519

520-
Queries are only executed as you access them through ``ng_query`` or ``ng_raw_query``. If you
521-
don't call those functions on any of the configured queries, none of them will be executed.
520+
Queries are only executed as you access them through ``ng_query``, ``ng_sudo_query``, ``ng_raw_query`` or ``ng_sudo_raw_query``.
521+
If you don't call those functions on any of the configured queries, none of them will be executed.
522522

523-
Both ``ng_query`` and ``ng_raw_query`` accept a single argument. This is the identifier of the
523+
``ng_query``, ``ng_sudo_query``, ``ng_raw_query`` and ``ng_sudo_raw_query`` accept a single argument. This is the identifier of the
524524
query, which is the key under the ``queries`` section, under which the query is configured.
525525

526526
Example usage of ``ng_query``:
@@ -537,6 +537,20 @@ Example usage of ``ng_query``:
537537
538538
{{ pagerfanta( images, 'twitter_bootstrap' ) }}
539539
540+
Example usage of ``ng_sudo_query``:
541+
542+
.. code-block:: twig
543+
544+
{% set users = ng_sudo_query( 'users' ) %}
545+
546+
<p>Total users: {{ users.nbResults }}</p>
547+
548+
{% for user in users %}
549+
<p>{{ user.content.name }}</p>
550+
{% endfor %}
551+
552+
{{ pagerfanta( users, 'twitter_bootstrap' ) }}
553+
540554
Example usage of ``ng_raw_query``:
541555

542556
.. code-block:: twig
@@ -547,13 +561,23 @@ Example usage of ``ng_raw_query``:
547561
<p>{{ categoryHit.valueObject.content.name }}: {{ categoryHit.valueObject.score }}</p>
548562
{% endfor %}
549563
564+
Example usage of ``ng_sudo_raw_query``:
565+
566+
.. code-block:: twig
567+
568+
{% set searchResult = ng_sudo_raw_query( 'users' ) %}
569+
570+
{% for userHit in searchResult.searchHits %}
571+
<p>{{ userHit.valueObject.content.name }}: {{ userHit.valueObject.score }}</p>
572+
{% endfor %}
573+
550574
.. note::
551575

552576
You can't execute named queries. They are only available for referencing in concrete query
553577
configuration for a particular view.
554578

555579
.. hint::
556580

557-
Execution of queries is **not cached**. If you call ``ng_query`` or ``ng_raw_query`` on the same
558-
query multiple times, the same query will be executed multiple times. If you need to access the
581+
Execution of queries is **not cached**. If you call ``ng_query``, ``ng_sudo_query``, ``ng_raw_query`` or ``ng_sudo_raw_query``
582+
on the same query multiple times, the same query will be executed multiple times. If you need to access the
559583
query result multiple times, store it in a variable and access the variable instead.

docs/reference/query_types/parameters/common/query/limit.rst.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Defines the maximum number of items to return.
55
If ``null`` is used as a value, the limit will be set to the default value.
66

7-
.. note:: This parameter will not be used if you execute the query from Twig using ``ng_query`` function.
7+
.. note:: This parameter will not be used if you execute the query from Twig using ``ng_query`` or ``ng_sudo_query`` functions.
88
In that case ``Pargerfanta`` pager is used with semantic parameters ``page`` and ``max_per_page``.
9-
To execute the query directly use ``ng_raw_query`` Twig function instead.
9+
To execute the query directly use ``ng_raw_query`` or ``ng_sudo_raw_query`` Twig functions instead.
1010

1111
- **value type**: ``integer``, ``null``
1212
- **value format**: ``single``

docs/reference/query_types/parameters/common/query/offset.rst.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Defines the offset for search hits, used for paging the results.
55
If ``null`` is used as a value, the offset will be set to the default value.
66

7-
.. note:: This parameter will not be used if you execute the query from Twig using ``ng_query`` function.
7+
.. note:: This parameter will not be used if you execute the query from Twig using ``ng_query`` or ``ng_sudo_query`` functions.
88
In that case ``Pargerfanta`` pager is used with semantic parameters ``page`` and ``max_per_page``.
9-
To execute the query directly use ``ng_raw_query`` Twig function instead.
9+
To execute the query directly use ``ng_raw_query`` or ``ng_sudo_raw_query`` Twig functions instead.
1010

1111
- **value type**: ``integer``, ``null``
1212
- **value format**: ``single``

docs/reference/templating.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ Site API provides four Twig functions for content rendering:
152152
<img src="{{ ng_image_alias( content.fields.image, 'large' ).uri }}" />
153153
154154
``ng_render_field`` and ``ng_image_alias`` are shown in more detail in the examples below. There are
155-
two other Twig functions, ``ng_query`` and ``ng_raw_query``. These are used with Query Types and are
156-
documented separately on :doc:`Query Types reference</reference/query_types>` documentation page.
155+
four other Twig functions, ``ng_query``, ``ng_sudo_query``, ``ng_raw_query`` and ``ng_sudo_raw_query``. These are used
156+
with Query Types and are documented separately on :doc:`Query Types reference</reference/query_types>` documentation page.
157157

158158
Basic usage
159159
-----------

lib/API/Values/Content.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,25 @@ abstract public function filterLocations(int $maxPerPage = 25, int $currentPage
9191
*/
9292
abstract public function getFieldRelation(string $fieldDefinitionIdentifier): ?self;
9393

94+
/**
95+
* Return single related Content from $fieldDefinitionIdentifier field using repository sudo.
96+
*/
97+
abstract public function getSudoFieldRelation(string $fieldDefinitionIdentifier): ?self;
98+
9499
/**
95100
* Return all related Content from $fieldDefinitionIdentifier.
96101
*
97102
* @return \Netgen\IbexaSiteApi\API\Values\Content[]
98103
*/
99104
abstract public function getFieldRelations(string $fieldDefinitionIdentifier, int $limit = 25): array;
100105

106+
/**
107+
* Return all related Content from $fieldDefinitionIdentifier using repository sudo.
108+
*
109+
* @return \Netgen\IbexaSiteApi\API\Values\Content[]
110+
*/
111+
abstract public function getSudoFieldRelations(string $fieldDefinitionIdentifier, int $limit = 25): array;
112+
101113
/**
102114
* Return related Content from $fieldDefinitionIdentifier field,
103115
* optionally limited by a list of $contentTypeIdentifiers.
@@ -113,18 +125,45 @@ abstract public function filterFieldRelations(
113125
int $currentPage = 1,
114126
): Pagerfanta;
115127

128+
/**
129+
* Return related Content from $fieldDefinitionIdentifier field using repository sudo,
130+
* optionally limited by a list of $contentTypeIdentifiers.
131+
*
132+
* @param string[] $contentTypeIdentifiers
133+
*
134+
* @return \Pagerfanta\Pagerfanta Pagerfanta instance iterating over Site API Content items
135+
*/
136+
abstract public function filterSudoFieldRelations(
137+
string $fieldDefinitionIdentifier,
138+
array $contentTypeIdentifiers = [],
139+
int $maxPerPage = 25,
140+
int $currentPage = 1,
141+
): Pagerfanta;
142+
116143
/**
117144
* Return single related Location from $fieldDefinitionIdentifier field.
118145
*/
119146
abstract public function getFieldRelationLocation(string $fieldDefinitionIdentifier): ?Location;
120147

148+
/**
149+
* Return single related Location from $fieldDefinitionIdentifier field using repository sudo.
150+
*/
151+
abstract public function getSudoFieldRelationLocation(string $fieldDefinitionIdentifier): ?Location;
152+
121153
/**
122154
* Return all related Locations from $fieldDefinitionIdentifier.
123155
*
124156
* @return \Netgen\IbexaSiteApi\API\Values\Location[]
125157
*/
126158
abstract public function getFieldRelationLocations(string $fieldDefinitionIdentifier, int $limit = 25): array;
127159

160+
/**
161+
* Return all related Locations from $fieldDefinitionIdentifier using repository sudo.
162+
*
163+
* @return \Netgen\IbexaSiteApi\API\Values\Location[]
164+
*/
165+
abstract public function getSudoFieldRelationLocations(string $fieldDefinitionIdentifier, int $limit = 25): array;
166+
128167
/**
129168
* Return related Locations from $fieldDefinitionIdentifier field,
130169
* optionally limited by a list of $contentTypeIdentifiers.
@@ -139,4 +178,19 @@ abstract public function filterFieldRelationLocations(
139178
int $maxPerPage = 25,
140179
int $currentPage = 1,
141180
): Pagerfanta;
181+
182+
/**
183+
* Return related Locations from $fieldDefinitionIdentifier field using repository sudo,
184+
* optionally limited by a list of $contentTypeIdentifiers.
185+
*
186+
* @param string[] $contentTypeIdentifiers
187+
*
188+
* @return \Pagerfanta\Pagerfanta Pagerfanta instance iterating over Site API Locations
189+
*/
190+
abstract public function filterSudoFieldRelationLocations(
191+
string $fieldDefinitionIdentifier,
192+
array $contentTypeIdentifiers = [],
193+
int $maxPerPage = 25,
194+
int $currentPage = 1,
195+
): Pagerfanta;
142196
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Netgen\IbexaSiteApi\Core\Site\Pagination\Pagerfanta;
6+
7+
use Ibexa\Contracts\Core\Repository\Repository;
8+
use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery;
9+
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
10+
use Ibexa\Contracts\Core\Repository\Values\Content\Search\SearchResult;
11+
use Netgen\IbexaSearchExtra\Core\Pagination\Pagerfanta\BaseAdapter;
12+
use Netgen\IbexaSiteApi\API\FilterService;
13+
14+
/**
15+
* Pagerfanta adapter performing search using FilterService and Repository sudo.
16+
*/
17+
final class SudoFilterAdapter extends BaseAdapter
18+
{
19+
public function __construct(
20+
Query $query,
21+
private readonly FilterService $filterService,
22+
private readonly Repository $repository,
23+
) {
24+
parent::__construct($query);
25+
}
26+
27+
protected function executeQuery(Query $query): SearchResult
28+
{
29+
if ($query instanceof LocationQuery) {
30+
return $this->repository->sudo(
31+
fn () => $this->filterService->filterLocations($query),
32+
);
33+
}
34+
35+
return $this->repository->sudo(
36+
fn () => $this->filterService->filterContent($query),
37+
);
38+
}
39+
}

0 commit comments

Comments
 (0)