Skip to content

Commit 2a99dc5

Browse files
committed
feat(stories): Add published_at_gt and other date related query parameters (#64)
1 parent 006cdab commit 2a99dc5

13 files changed

+586
-11
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,38 @@ new OrFilter(
309309
);
310310
```
311311

312+
#### Filtering by native date fields
313+
314+
The Storyblok API allows filtering by publish or updated dates.
315+
Those fields could not be filtered by `gt_date` or `lt_date` operations and have dedicated parameters in the request.
316+
317+
Supported date parameters are:
318+
* `published_at_gt`
319+
* `published_at_lt`
320+
* `first_published_at_gt`
321+
* `first_published_at_lt`
322+
* `updated_at_gt`
323+
* `updated_at_lt`
324+
325+
```php
326+
use Storyblok\Api\StoriesApi;
327+
use Storyblok\Api\StoryblokClient;
328+
use Storyblok\Api\Domain\Value\QueryParameter\Operator;
329+
use Storyblok\Api\Domain\Value\QueryParameter\PublishedAtQueryParameter;
330+
use Storyblok\Api\Domain\Value\QueryParameter\QueryParameterCollection;
331+
use Storyblok\Api\Request\StoriesRequest;
332+
333+
$client = new StoryblokClient(/* ... */);
334+
335+
$storiesApi = new StoriesApi($client);
336+
$response = $storiesApi->all(new StoriesRequest(
337+
language: 'de',
338+
queryParameterCollection: new QueryParameterCollection([
339+
new PublishedAtQueryParameter(new DateTimeImmutable(), Operator::GreaterThan)
340+
])
341+
));
342+
```
343+
312344
### Get all available stories by Content Type (`string`)
313345

314346
```php
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
use Webmozart\Assert\Assert;
18+
19+
/**
20+
* Represents top level query parameters which are holding simple string values.
21+
*
22+
* @author Frank Stelzer <[email protected]>
23+
*/
24+
abstract readonly class DateQueryParameter extends QueryParameter
25+
{
26+
protected function validateValue(string $value): void
27+
{
28+
parent::validateValue($value);
29+
30+
Assert::regex(
31+
$value,
32+
'/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/',
33+
\sprintf('The date must be in the format YYYY-MM-DD HH:MM, given: %s', $value),
34+
);
35+
}
36+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
final readonly class FirstPublishedAtQueryParameter extends DateQueryParameter
18+
{
19+
public const string FIRST_PUBLISHED_AT_GT = 'first_published_at_gt';
20+
public const string FIRST_PUBLISHED_AT_LT = 'first_published_at_lt';
21+
22+
public function __construct(\DateTimeInterface $publishedAt, Operator $operator)
23+
{
24+
$name = match ($operator->value) {
25+
'lt' => self::FIRST_PUBLISHED_AT_LT,
26+
default => self::FIRST_PUBLISHED_AT_GT,
27+
};
28+
29+
parent::__construct($name, $publishedAt->format('Y-m-d H:i'));
30+
}
31+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
enum Operator: string
18+
{
19+
case GreaterThan = 'gt';
20+
case LessThan = 'lt';
21+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
final readonly class PublishedAtQueryParameter extends DateQueryParameter
18+
{
19+
public const string PUBLISHED_AT_GT = 'published_at_gt';
20+
public const string PUBLISHED_AT_LT = 'published_at_lt';
21+
22+
public function __construct(\DateTimeInterface $publishedAt, Operator $operator)
23+
{
24+
$name = match ($operator->value) {
25+
'lt' => self::PUBLISHED_AT_LT,
26+
default => self::PUBLISHED_AT_GT,
27+
};
28+
29+
parent::__construct($name, $publishedAt->format('Y-m-d H:i'));
30+
}
31+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
use OskarStark\Value\TrimmedNonEmptyString;
18+
19+
/**
20+
* Represents top level query parameters which are holding simple string values.
21+
*
22+
* @author Frank Stelzer <[email protected]>
23+
*/
24+
abstract readonly class QueryParameter
25+
{
26+
public function __construct(
27+
public string $name,
28+
public string $value,
29+
) {
30+
$this->validateName($name);
31+
$this->validateValue($value);
32+
}
33+
34+
protected function validateName(string $name): void
35+
{
36+
TrimmedNonEmptyString::fromString($name);
37+
}
38+
39+
protected function validateValue(string $value): void
40+
{
41+
TrimmedNonEmptyString::fromString($value);
42+
}
43+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
/**
18+
* @author Frank Stelzer <[email protected]>
19+
* @author Silas Joisten <[email protected]>
20+
*
21+
* @implements \IteratorAggregate<int, QueryParameter>
22+
*/
23+
final class QueryParameterCollection implements \Countable, \IteratorAggregate
24+
{
25+
/**
26+
* @var QueryParameter[]
27+
*/
28+
private array $items = [];
29+
30+
/**
31+
* @param QueryParameter[] $items
32+
*/
33+
public function __construct(
34+
array $items = [],
35+
) {
36+
foreach ($items as $item) {
37+
$this->add($item);
38+
}
39+
}
40+
41+
/**
42+
* @return \Traversable<int, QueryParameter>
43+
*/
44+
public function getIterator(): \Traversable
45+
{
46+
return new \ArrayIterator($this->items);
47+
}
48+
49+
public function count(): int
50+
{
51+
return \count($this->items);
52+
}
53+
54+
public function add(QueryParameter $queryParameter): void
55+
{
56+
if ($this->has($queryParameter)) {
57+
return;
58+
}
59+
60+
$this->items[] = $queryParameter;
61+
}
62+
63+
public function has(QueryParameter $queryParameter): bool
64+
{
65+
foreach ($this->items as $item) {
66+
if ($item->name === $queryParameter->name) {
67+
return true;
68+
}
69+
}
70+
71+
return false;
72+
}
73+
74+
public function remove(QueryParameter $queryParameter): void
75+
{
76+
foreach ($this->items as $key => $item) {
77+
if ($item->name === $queryParameter->name) {
78+
unset($this->items[$key]);
79+
80+
break;
81+
}
82+
}
83+
}
84+
85+
/**
86+
* @return array{
87+
* published_at_gt?: string,
88+
* published_at_lt?: string,
89+
* first_published_at_gt?: string,
90+
* first_published_at_lt?: string,
91+
* updated_at_gt?: string,
92+
* updated_at_lt?: string,
93+
* }
94+
*/
95+
public function toArray(): array
96+
{
97+
$result = [];
98+
99+
foreach ($this->items as $queryParameter) {
100+
$result[$queryParameter->name] = $queryParameter->value;
101+
}
102+
103+
return $result;
104+
}
105+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of storyblok/php-content-api-client.
7+
*
8+
* (c) Storyblok GmbH <[email protected]>
9+
* in cooperation with SensioLabs Deutschland <[email protected]>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Storyblok\Api\Domain\Value\QueryParameter;
16+
17+
final readonly class UpdatedAtQueryParameter extends DateQueryParameter
18+
{
19+
public const string UPDATED_AT_GT = 'updated_at_gt';
20+
public const string UPDATED_AT_LT = 'updated_at_lt';
21+
22+
public function __construct(\DateTimeInterface $publishedAt, Operator $operator)
23+
{
24+
$name = match ($operator->value) {
25+
'lt' => self::UPDATED_AT_LT,
26+
default => self::UPDATED_AT_GT,
27+
};
28+
29+
parent::__construct($name, $publishedAt->format('Y-m-d H:i'));
30+
}
31+
}

src/Request/StoriesRequest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Storyblok\Api\Domain\Value\Field\FieldCollection;
2121
use Storyblok\Api\Domain\Value\Filter\FilterCollection;
2222
use Storyblok\Api\Domain\Value\IdCollection;
23+
use Storyblok\Api\Domain\Value\QueryParameter\QueryParameterCollection;
2324
use Storyblok\Api\Domain\Value\Resolver\RelationCollection;
2425
use Storyblok\Api\Domain\Value\Resolver\ResolveLinks;
2526
use Storyblok\Api\Domain\Value\Slug\Slug;
@@ -49,6 +50,8 @@ public function __construct(
4950
public ResolveLinks $resolveLinks = new ResolveLinks(),
5051
public SlugCollection $excludeSlugs = new SlugCollection(),
5152
public ?Slug $startsWith = null,
53+
public QueryParameterCollection $queryParameterCollection = new QueryParameterCollection(
54+
),
5255
) {
5356
Assert::stringNotEmpty($language);
5457
Assert::lessThanEq($this->pagination->perPage, self::MAX_PER_PAGE);
@@ -71,6 +74,12 @@ public function __construct(
7174
* version?: string,
7275
* excluding_slugs?: string,
7376
* starts_with?: string,
77+
* published_at_gt?: string,
78+
* published_at_lt?: string,
79+
* first_published_at_gt?: string,
80+
* first_published_at_lt?: string,
81+
* updated_at_gt?: string,
82+
* updated_at_lt?: string,
7483
* }
7584
*/
7685
public function toArray(): array
@@ -126,6 +135,10 @@ public function toArray(): array
126135
$array['starts_with'] = $this->startsWith->value;
127136
}
128137

138+
if ($this->queryParameterCollection->count() > 0) {
139+
$array = array_merge($array, $this->queryParameterCollection->toArray());
140+
}
141+
129142
return $array;
130143
}
131144
}

0 commit comments

Comments
 (0)