allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
This commit is contained in:
15
vendor/beste/clock/.github/dependabot.yml
vendored
Normal file
15
vendor/beste/clock/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
include: "scope"
|
||||
prefix: "github-actions"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependency"
|
||||
2
vendor/beste/clock/.github/settings.yml
vendored
Normal file
2
vendor/beste/clock/.github/settings.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# https://probot.github.io/apps/settings/
|
||||
_extends: beste/.github
|
||||
23
vendor/beste/clock/.github/workflows/dependabot-auto-merge.yml
vendored
Normal file
23
vendor/beste/clock/.github/workflows/dependabot-auto-merge.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: "Dependabot auto-merge"
|
||||
|
||||
on: [pull_request_target] # yamllint disable-line rule:truthy
|
||||
|
||||
permissions:
|
||||
contents: "write"
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: "ubuntu-latest"
|
||||
if: "${{ github.actor == 'dependabot[bot]' }}"
|
||||
steps:
|
||||
- name: "Dependabot metadata"
|
||||
id: "metadata"
|
||||
uses: "dependabot/fetch-metadata@v1.3.5"
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: "Enable auto-merge for Dependabot PRs"
|
||||
if: "${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }}"
|
||||
run: "gh pr merge --auto --merge \"$PR_URL\""
|
||||
env:
|
||||
PR_URL: "${{github.event.pull_request.html_url}}"
|
||||
GITHUB_TOKEN: "${{secrets.GITHUB_TOKEN}}"
|
||||
50
vendor/beste/clock/.github/workflows/tests.yml
vendored
Normal file
50
vendor/beste/clock/.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- '1.x'
|
||||
- '2.x'
|
||||
- '3.x'
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: PHP ${{ matrix.php }}
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php:
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
tools: composer:v2
|
||||
coverage: xdebug
|
||||
env:
|
||||
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: "ramsey/composer-install@v2"
|
||||
|
||||
- name: Setup problem matchers for PHP
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
|
||||
- name: Run PHPStan
|
||||
run: vendor/bin/phpstan analyse --error-format=github
|
||||
|
||||
- name: Run Psalm
|
||||
run: vendor/bin/psalm --output-format=github
|
||||
|
||||
- name: Setup Problem Matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Run PHPUnit
|
||||
run: vendor/bin/phpunit --testdox --coverage-text
|
||||
24
vendor/beste/clock/CHANGELOG.md
vendored
Normal file
24
vendor/beste/clock/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 3.0.0 - 2022-11-26
|
||||
This release replaces `stella-maris/clock` with `psr/clock`.
|
||||
|
||||
## 2.3.1 - 2022-11-25
|
||||
This release reverts the change to implement `psr/clock` directly, to not break dependents who rely on `stella-maris/clock`
|
||||
|
||||
## 2.3.0 - 2022-11-25
|
||||
This release re-introduces support for PHP ^8.0 and implements the freshly released `psr/clock` (PSR-20) directly.
|
||||
|
||||
## 2.2.0 - 2022-11-04
|
||||
This release drops support for PHP <8.1.
|
||||
|
||||
## 2.1.0 - 2022-04-22
|
||||
Adds the `WrappingClock` which allows using an object with a `now()` method returning a `DateTimeImmutable` object
|
||||
as a "real" clock.
|
||||
|
||||
## 2.0.0 - 2022-04-20
|
||||
This release introduces a compatibility layer with the PSR-20 draft, allowing us to already
|
||||
get some interoperability by depending on a shared interface.
|
||||
|
||||
## 1.0.0 - 2021-12-10
|
||||
Initial Release
|
||||
21
vendor/beste/clock/LICENSE
vendored
Normal file
21
vendor/beste/clock/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Jérôme Gamez, https://github.com/beste <jerome@gamez.name>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
182
vendor/beste/clock/README.md
vendored
Normal file
182
vendor/beste/clock/README.md
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
# Clock
|
||||
|
||||
[](https://packagist.org/packages/beste/clock)
|
||||
[](https://packagist.org/packages/beste/clock)
|
||||
[](https://github.com/beste/clock/actions/workflows/tests.yml)
|
||||
|
||||
A collection of Clock implementations.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Clocks](#clocks)
|
||||
- [`SystemClock`](#systemclock) - Time, as your computer (k)nows it
|
||||
- [`LocalizedClock`](#localizedclock) - A clock in a(nother) time zone
|
||||
- [`UTCClock`](#utcclock) - The clock that you should™ use
|
||||
- [`FrozenClock`](#frozenclock) - A clock that stopped moving (perfect for tests)
|
||||
- [`MinuteClock`](#minuteclock) - Who cares about seconds or even less?
|
||||
- [`WrappingClock`](#wrappingclock) - Allows wrapping a non-clock with a `now()` method in a clock
|
||||
- [Running Tests](#running-tests)
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
composer require beste/clock
|
||||
```
|
||||
|
||||
## Clocks
|
||||
|
||||
### `SystemClock`
|
||||
|
||||
A System Clock will return a time just as if you would use `new DateTimeImmutable()`. The time zone of the returned
|
||||
value is determined by the clock's environment, for example by the time zone that has been configured in your
|
||||
application, by a previously used `date_default_timezone_set()` or by the value of `date.timezone` in the
|
||||
`php.ini`. If none of these are explicitly set, it uses the `UTC` timezone.
|
||||
|
||||
```php
|
||||
# examples/system_clock.php
|
||||
|
||||
use Beste\Clock\SystemClock;
|
||||
|
||||
$clock = SystemClock::create();
|
||||
|
||||
printf("On your system, the current date and time is %s\n", $clock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
|
||||
date_default_timezone_set('America/Los_Angeles');
|
||||
|
||||
printf("Now it's %s\n", $clock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
|
||||
date_default_timezone_set('Europe/Berlin');
|
||||
|
||||
printf("Now it's %s\n", $clock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
```
|
||||
|
||||
### `LocalizedClock`
|
||||
|
||||
A localized clock is aware of the time zone in which it is located. While the time zone of the `SystemClock` is
|
||||
determined from the environment (your PHP configuration), this clock uses the time zone that you initialize it with.
|
||||
|
||||
```php
|
||||
# examples/localized_clock.php
|
||||
|
||||
use Beste\Clock\LocalizedClock;
|
||||
|
||||
$berlin = LocalizedClock::in('Europe/Berlin');
|
||||
$denver = LocalizedClock::in(new DateTimeZone('America/Denver'));
|
||||
|
||||
printf("Berlin: %s\n", $berlin->now()->format('Y-m-d H:i:s T (P)'));
|
||||
printf("Denver: %s\n", $denver->now()->format('Y-m-d H:i:s T (P)'));
|
||||
```
|
||||
|
||||
### `UTCClock`
|
||||
|
||||
`UTC` is the abbreviation for [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time)
|
||||
and a special kind of time zone that is not affected by daylight saving time. It is commonly used for the communication
|
||||
of time across different systems (e.g. between your PHP application and a database, or between a backend
|
||||
and a frontend). An `UTCClock` instance behaves exactly the same as an instance of `LocalizedClock::in('UTC')`.
|
||||
|
||||
```php
|
||||
# examples/utc_clock.php
|
||||
|
||||
use Beste\Clock\UTCClock;
|
||||
|
||||
$clock = UTCClock::create();
|
||||
|
||||
$anotherTimeZone = 'Africa/Casablanca';
|
||||
|
||||
date_default_timezone_set($anotherTimeZone);
|
||||
|
||||
printf("The system time zone is %s.\n", $anotherTimeZone);
|
||||
printf("The clock's time zone is %s.\n", $clock->now()->getTimezone()->getName());
|
||||
```
|
||||
|
||||
### `FrozenClock`
|
||||
|
||||
A frozen clock doesn't move - the time we set it with will stay the same... unless we change it. That makes the
|
||||
frozen clock perfect for testing the behaviour of your time-based use cases, for example in Unit Tests.
|
||||
|
||||
```php
|
||||
# examples/frozen_clock.php
|
||||
|
||||
use Beste\Clock\FrozenClock;
|
||||
use Beste\Clock\SystemClock;
|
||||
|
||||
$frozenClock = FrozenClock::withNowFrom(SystemClock::create());
|
||||
|
||||
printf("\nThe clock is frozen at %s", $frozenClock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
printf("\nLet's wait a second…");
|
||||
sleep(1);
|
||||
printf("\nIt's one second later, but the clock is still frozen at %s", $frozenClock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
|
||||
$frozenClock->setTo($frozenClock->now()->modify('-5 minutes'));
|
||||
printf("\nAfter turning back the clock 5 minutes, it's %s", $frozenClock->now()->format('Y-m-d H:i:s T (P)'));
|
||||
```
|
||||
|
||||
### `MinuteClock`
|
||||
|
||||
In some cases, microseconds, milliseconds, or even seconds are too precise for some use cases - sometimes it's just
|
||||
enough if something happened in the same minute. Using the minute
|
||||
|
||||
```php
|
||||
# examples/minute_clock.php
|
||||
|
||||
use Beste\Clock\FrozenClock;
|
||||
use Beste\Clock\MinuteClock;
|
||||
|
||||
$frozenClock = FrozenClock::at(new DateTimeImmutable('01:23:45'));
|
||||
$clock = MinuteClock::wrapping($frozenClock);
|
||||
|
||||
printf("For %s, the minute clock returns %s\n",
|
||||
$frozenClock->now()->format('H:i:s'),
|
||||
$clock->now()->format('H:i:s')
|
||||
);
|
||||
|
||||
$frozenClock->setTo($frozenClock->now()->modify('+10 seconds')); // 01:23:55
|
||||
|
||||
printf("For %s, the minute clock still returns %s\n",
|
||||
$frozenClock->now()->format('H:i:s'),
|
||||
$clock->now()->format('H:i:s')
|
||||
);
|
||||
```
|
||||
|
||||
### `WrappingClock`
|
||||
|
||||
If you already have an object with a `now()` method returning a `DateTimeImmutable` object, you can wrap it
|
||||
in a `WrappingClock` to make it a "real" Clock.
|
||||
|
||||
as a "real" clock.
|
||||
|
||||
```php
|
||||
# examples/wrapping_clock.php
|
||||
|
||||
use Beste\Clock\WrappingClock;
|
||||
|
||||
// Create a frozen $now so that we can test the wrapping clock.
|
||||
$now = new DateTimeImmutable('2012-04-24 12:00:00');
|
||||
|
||||
// Create an object that is NOT a clock, but has a now() method returning the frozen $now.
|
||||
$clock = new class($now) {
|
||||
private \DateTimeImmutable $now;
|
||||
|
||||
public function __construct(\DateTimeImmutable $now)
|
||||
{
|
||||
$this->now = $now;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
return $this->now;
|
||||
}
|
||||
};
|
||||
|
||||
// We can now wrap the object in a clock.
|
||||
$wrappedClock = WrappingClock::wrapping($clock);
|
||||
|
||||
assert($now->format(DATE_ATOM) === $wrappedClock->now()->format(DATE_ATOM));
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
```shell
|
||||
composer test
|
||||
```
|
||||
58
vendor/beste/clock/composer.json
vendored
Normal file
58
vendor/beste/clock/composer.json
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "beste/clock",
|
||||
"type": "library",
|
||||
"description": "A collection of Clock implementations",
|
||||
"keywords": ["clock", "clock-interface", "psr20", "psr-20"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jérôme Gamez",
|
||||
"email": "jerome@gamez.name"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"psr/clock": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9.1",
|
||||
"phpstan/phpstan-phpunit": "^1.2.2",
|
||||
"phpstan/phpstan-strict-rules": "^1.4.4",
|
||||
"phpunit/phpunit": "^9.5.26",
|
||||
"psalm/plugin-phpunit": "^0.16.1",
|
||||
"vimeo/psalm": "^4.29"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Beste\\Clock\\": "src/Clock"
|
||||
},
|
||||
"files": [
|
||||
"src/Clock.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Beste\\Clock\\Tests\\": "tests/Clock"
|
||||
}
|
||||
},
|
||||
"provide": {
|
||||
"psr/clock-implementation": "1.0"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"@phpstan",
|
||||
"@psalm",
|
||||
"@phpunit"
|
||||
],
|
||||
"phpunit": "vendor/bin/phpunit",
|
||||
"phpstan": "vendor/bin/phpstan analyse",
|
||||
"psalm": "vendor/bin/psalm"
|
||||
}
|
||||
}
|
||||
12
vendor/beste/clock/src/Clock.php
vendored
Normal file
12
vendor/beste/clock/src/Clock.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste;
|
||||
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
interface Clock extends ClockInterface
|
||||
{
|
||||
|
||||
}
|
||||
47
vendor/beste/clock/src/Clock/FrozenClock.php
vendored
Normal file
47
vendor/beste/clock/src/Clock/FrozenClock.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
final class FrozenClock implements Clock
|
||||
{
|
||||
private DateTimeImmutable $frozenAt;
|
||||
|
||||
private function __construct(DateTimeImmutable $frozenAt)
|
||||
{
|
||||
$this->frozenAt = $frozenAt;
|
||||
}
|
||||
|
||||
public static function at(DateTimeImmutable $time): self
|
||||
{
|
||||
return new self($time);
|
||||
}
|
||||
|
||||
public static function withNowFrom(ClockInterface $clock): self
|
||||
{
|
||||
return new self($clock->now());
|
||||
}
|
||||
|
||||
public static function fromUTC(): self
|
||||
{
|
||||
return new self(new DateTimeImmutable('now', new DateTimeZone('UTC')));
|
||||
}
|
||||
|
||||
public function setTo(DateTimeImmutable $time): self
|
||||
{
|
||||
$this->frozenAt = $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return clone $this->frozenAt;
|
||||
}
|
||||
}
|
||||
42
vendor/beste/clock/src/Clock/LocalizedClock.php
vendored
Normal file
42
vendor/beste/clock/src/Clock/LocalizedClock.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
final class LocalizedClock implements Clock
|
||||
{
|
||||
private DateTimeZone $timeZone;
|
||||
|
||||
private function __construct(DateTimeZone $timeZone)
|
||||
{
|
||||
$this->timeZone = $timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeZone|string $timeZone
|
||||
*/
|
||||
public static function in($timeZone): self
|
||||
{
|
||||
if (is_string($timeZone)) {
|
||||
try {
|
||||
$timeZone = new DateTimeZone($timeZone);
|
||||
} catch (Throwable $e) {
|
||||
throw new InvalidArgumentException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return new self($timeZone);
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return new DateTimeImmutable('now', $this->timeZone);
|
||||
}
|
||||
}
|
||||
37
vendor/beste/clock/src/Clock/MinuteClock.php
vendored
Normal file
37
vendor/beste/clock/src/Clock/MinuteClock.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
final class MinuteClock implements Clock
|
||||
{
|
||||
private ClockInterface $clock;
|
||||
|
||||
private function __construct(ClockInterface $clock)
|
||||
{
|
||||
$this->clock = $clock;
|
||||
}
|
||||
|
||||
public static function wrapping(ClockInterface $clock): self
|
||||
{
|
||||
return new self($clock);
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return $this->floor($this->clock->now());
|
||||
}
|
||||
|
||||
private function floor(DateTimeImmutable $now): DateTimeImmutable
|
||||
{
|
||||
return $now->setTime(
|
||||
(int) $now->format('H'),
|
||||
(int) $now->format('i')
|
||||
);
|
||||
}
|
||||
}
|
||||
25
vendor/beste/clock/src/Clock/SystemClock.php
vendored
Normal file
25
vendor/beste/clock/src/Clock/SystemClock.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
|
||||
final class SystemClock implements Clock
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return new DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
29
vendor/beste/clock/src/Clock/UTCClock.php
vendored
Normal file
29
vendor/beste/clock/src/Clock/UTCClock.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
final class UTCClock implements Clock
|
||||
{
|
||||
private DateTimeZone $timeZone;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->timeZone = new DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return new DateTimeImmutable('now', $this->timeZone);
|
||||
}
|
||||
}
|
||||
61
vendor/beste/clock/src/Clock/WrappingClock.php
vendored
Normal file
61
vendor/beste/clock/src/Clock/WrappingClock.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
final class WrappingClock implements Clock
|
||||
{
|
||||
private ClockInterface $wrappedClock;
|
||||
|
||||
private function __construct(ClockInterface $wrappedClock)
|
||||
{
|
||||
$this->wrappedClock = $wrappedClock;
|
||||
}
|
||||
|
||||
public static function wrapping(object $clock): self
|
||||
{
|
||||
if ($clock instanceof ClockInterface) {
|
||||
return new self($clock);
|
||||
}
|
||||
|
||||
if (!method_exists($clock, 'now')) {
|
||||
throw new \InvalidArgumentException('$clock must implement StellaMaris\Clock\ClockInterface or have a now() method');
|
||||
}
|
||||
|
||||
if (!($clock->now() instanceof DateTimeImmutable)) {
|
||||
throw new \InvalidArgumentException('$clock->now() must return a DateTimeImmutable');
|
||||
}
|
||||
|
||||
$wrappedClock = new class($clock) implements ClockInterface {
|
||||
private object $clock;
|
||||
|
||||
public function __construct(object $clock)
|
||||
{
|
||||
$this->clock = $clock;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
assert(method_exists($this->clock, 'now'));
|
||||
|
||||
$now = $this->clock->now();
|
||||
|
||||
assert($now instanceof \DateTimeImmutable);
|
||||
|
||||
return $now;
|
||||
}
|
||||
};
|
||||
|
||||
return new self($wrappedClock);
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return $this->wrappedClock->now();
|
||||
}
|
||||
}
|
||||
35
vendor/beste/in-memory-cache/CHANGELOG.md
vendored
Normal file
35
vendor/beste/in-memory-cache/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# CHANGELOG
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 1.4.0 - 2025-09-30
|
||||
|
||||
* Added support for PHP 8.5
|
||||
|
||||
## 1.3.1 - 2024-08-26
|
||||
|
||||
* Made clock argument of `InMemoryCache` constructor explicitly nullable
|
||||
([#4](https://github.com/beste/in-memory-cache-php/pull/4))
|
||||
|
||||
## 1.3.0 - 2024-08-17
|
||||
|
||||
* Added support for PHP 8.4
|
||||
|
||||
## 1.2.0 - 2024-07-27
|
||||
|
||||
* The [PSR-6 definition on what makes a valid cache key](https://www.php-fig.org/psr/psr-6/#definitions), it is said that
|
||||
keys must support keys consisting of the characters `A-Z`, `a-z`, `0-9`, `_`, and `.` in any order in UTF-8
|
||||
encoding and a length of up to 64 characters. Implementing libraries MAY support additional characters and encodings
|
||||
or longer lengths, but must support at least that minimum.
|
||||
* Dashes (`-`) are now allowed in cache keys.
|
||||
* The arbitrary maximum key length of 64 characters has been removed.
|
||||
|
||||
|
||||
## 1.1.0 - 2024-03-02
|
||||
|
||||
* The Cache can now be instantiated without providing a [PSR-20](https://www.php-fig.org/psr/psr-20/) clock implementation.
|
||||
* The library doesn't depend on the [`beste/clock` library](https://github.com/beste/clock) anymore.
|
||||
|
||||
## 1.0.0 - 2023-12-09
|
||||
|
||||
Initial Release
|
||||
21
vendor/beste/in-memory-cache/LICENSE
vendored
Normal file
21
vendor/beste/in-memory-cache/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Jérôme Gamez, https://github.com/beste <jerome@gamez.name>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
69
vendor/beste/in-memory-cache/README.md
vendored
Normal file
69
vendor/beste/in-memory-cache/README.md
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# PSR-6 In-Memory Cache
|
||||
|
||||
A [PSR-6](https://www.php-fig.org/psr/psr-6/) In-Memory cache that can be used as a default implementation and in tests.
|
||||
|
||||
[](https://packagist.org/packages/beste/in-memory-cache)
|
||||
[](https://packagist.org/packages/beste/in-memory-cache)
|
||||
[](https://packagist.org/packages/beste/in-memory-cache/stats)
|
||||
[](https://packagist.org/packages/beste/in-memory-cache/stats)
|
||||
[](https://github.com/beste/in-memory-cache-php/actions/workflows/tests.yml)
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
composer require beste/in-memory-cache
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
use Beste\Cache\InMemoryCache;
|
||||
|
||||
$cache = new InMemoryCache();
|
||||
|
||||
$item = $cache->getItem('key');
|
||||
|
||||
assert($item->isHit() === false);
|
||||
assert($item->get() === null);
|
||||
|
||||
$item->set('value');
|
||||
$cache->save($item);
|
||||
|
||||
// Later...
|
||||
|
||||
$item = $cache->getItem('key');
|
||||
|
||||
assert($item->isHit() === true);
|
||||
assert($item->get() === 'value');
|
||||
```
|
||||
|
||||
You can also provide your own [PSR-20](https://www.php-fig.org/psr/psr-20/) clock implementation, for example a frozen
|
||||
clock for testing, for example from the [`beste/clock` library](https://github.com/beste/clock).
|
||||
|
||||
```php
|
||||
use Beste\Clock\FrozenClock;
|
||||
use Beste\Cache\InMemoryCache;
|
||||
|
||||
$clock = FrozenClock::fromUTC()
|
||||
$cache = new InMemoryCache();
|
||||
|
||||
$item = $cache->getItem('key');
|
||||
$item->set('value')->expiresAfter(new DateInterval('PT5M'));
|
||||
$cache->save($item);
|
||||
|
||||
$clock->setTo($clock->now()->add(new DateInterval('PT2M')));
|
||||
assert($cache->getItem('key')->isHit() === true);
|
||||
|
||||
$clock->setTo($clock->now()->add(new DateInterval('PT5M')));
|
||||
assert($cache->getItem('key')->isHit() === false);
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
```shell
|
||||
composer test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is published under the [MIT License](LICENSE).
|
||||
67
vendor/beste/in-memory-cache/composer.json
vendored
Normal file
67
vendor/beste/in-memory-cache/composer.json
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "beste/in-memory-cache",
|
||||
"description": "A PSR-6 In-Memory cache that can be used as a fallback implementation and/or in tests.",
|
||||
"keywords": ["cache", "psr-6", "beste"],
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jérôme Gamez",
|
||||
"email": "jerome@gamez.name"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"psr/cache": "^2.0 || ^3.0",
|
||||
"psr/clock": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"beste/clock": "^3.0",
|
||||
"beste/php-cs-fixer-config": "^3.2.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.62.0",
|
||||
"phpstan/extension-installer": "^1.4.1",
|
||||
"phpstan/phpstan": "^2.0.1",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^10.5.2 || ^11.3.1",
|
||||
"symfony/var-dumper": "^6.4 || ^7.1.3"
|
||||
},
|
||||
"provide": {
|
||||
"psr/cache-implementation": "2.0 || 3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/clock-implementation": "Allows injecting a Clock, for example a frozen clock for testing"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Beste\\Cache\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Beste\\Cache\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"analyse": "vendor/bin/phpstan analyse",
|
||||
"analyze": "@analyse",
|
||||
"cs-fix": "vendor/bin/php-cs-fixer fix --diff --verbose",
|
||||
"test": "vendor/bin/phpunit --testdox",
|
||||
"test-coverage": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"XDEBUG_MODE=coverage vendor/bin/phpunit --testdox --coverage-html=.build/coverage"
|
||||
],
|
||||
"check": [
|
||||
"@cs-fix",
|
||||
"@analyse",
|
||||
"@test"
|
||||
]
|
||||
}
|
||||
}
|
||||
81
vendor/beste/in-memory-cache/src/CacheItem.php
vendored
Normal file
81
vendor/beste/in-memory-cache/src/CacheItem.php
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Beste\Cache;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CacheItem implements CacheItemInterface
|
||||
{
|
||||
private mixed $value;
|
||||
private ?\DateTimeInterface $expiresAt;
|
||||
private bool $isHit;
|
||||
|
||||
public function __construct(private readonly CacheKey $key, private readonly ClockInterface $clock)
|
||||
{
|
||||
$this->value = null;
|
||||
$this->expiresAt = null;
|
||||
$this->isHit = false;
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return $this->key->toString();
|
||||
}
|
||||
|
||||
public function get(): mixed
|
||||
{
|
||||
if ($this->isHit()) {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isHit(): bool
|
||||
{
|
||||
if ($this->isHit === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->expiresAt === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->clock->now()->getTimestamp() < $this->expiresAt->getTimestamp();
|
||||
}
|
||||
|
||||
public function set(mixed $value): static
|
||||
{
|
||||
$this->isHit = true;
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function expiresAt(?\DateTimeInterface $expiration): static
|
||||
{
|
||||
$this->expiresAt = $expiration;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function expiresAfter(\DateInterval|int|null $time): static
|
||||
{
|
||||
if ($time === null) {
|
||||
$this->expiresAt = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_int($time)) {
|
||||
$time = new \DateInterval("PT{$time}S");
|
||||
}
|
||||
|
||||
$this->expiresAt = $this->clock->now()->add($time);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
25
vendor/beste/in-memory-cache/src/CacheKey.php
vendored
Normal file
25
vendor/beste/in-memory-cache/src/CacheKey.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Beste\Cache;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CacheKey
|
||||
{
|
||||
private function __construct(private readonly string $value) {}
|
||||
|
||||
public static function fromString(string $value): self
|
||||
{
|
||||
if (preg_match('/^[a-zA-Z0-9_.-]+$/u', $value) !== 1) {
|
||||
throw InvalidArgument::invalidKey();
|
||||
}
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
119
vendor/beste/in-memory-cache/src/InMemoryCache.php
vendored
Normal file
119
vendor/beste/in-memory-cache/src/InMemoryCache.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Beste\Cache;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
final class InMemoryCache implements CacheItemPoolInterface
|
||||
{
|
||||
private readonly ClockInterface $clock;
|
||||
|
||||
/** @var array<string, CacheItemInterface> */
|
||||
private array $items;
|
||||
/** @var array<string, CacheItemInterface> */
|
||||
private array $deferredItems;
|
||||
|
||||
public function __construct(
|
||||
?ClockInterface $clock = null,
|
||||
) {
|
||||
$this->clock = $clock ?? new class implements ClockInterface {
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return new DateTimeImmutable();
|
||||
}
|
||||
|
||||
};
|
||||
$this->items = [];
|
||||
$this->deferredItems = [];
|
||||
}
|
||||
|
||||
public function getItem(string $key): CacheItemInterface
|
||||
{
|
||||
$key = CacheKey::fromString($key);
|
||||
|
||||
$item = $this->items[$key->toString()] ?? null;
|
||||
|
||||
if ($item === null) {
|
||||
return new CacheItem($key, $this->clock);
|
||||
}
|
||||
|
||||
return clone $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iterable<CacheItemInterface>
|
||||
*/
|
||||
public function getItems(array $keys = []): iterable
|
||||
{
|
||||
if ($keys === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$items[$key] = $this->getItem($key);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function hasItem(string $key): bool
|
||||
{
|
||||
return $this->getItem($key)->isHit();
|
||||
}
|
||||
|
||||
public function clear(): bool
|
||||
{
|
||||
$this->items = [];
|
||||
$this->deferredItems = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteItem(string $key): bool
|
||||
{
|
||||
$key = CacheKey::fromString($key);
|
||||
|
||||
unset($this->items[$key->toString()]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteItems(array $keys): bool
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$this->deleteItem($key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function save(CacheItemInterface $item): bool
|
||||
{
|
||||
$this->items[$item->getKey()] = $item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function saveDeferred(CacheItemInterface $item): bool
|
||||
{
|
||||
$this->deferredItems[$item->getKey()] = $item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function commit(): bool
|
||||
{
|
||||
foreach ($this->deferredItems as $item) {
|
||||
$this->save($item);
|
||||
}
|
||||
|
||||
$this->deferredItems = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
11
vendor/beste/in-memory-cache/src/InvalidArgument.php
vendored
Normal file
11
vendor/beste/in-memory-cache/src/InvalidArgument.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Beste\Cache;
|
||||
|
||||
final class InvalidArgument extends \InvalidArgumentException implements \Psr\Cache\InvalidArgumentException
|
||||
{
|
||||
public static function invalidKey(): self
|
||||
{
|
||||
return new self('The given key is not valid');
|
||||
}
|
||||
}
|
||||
2
vendor/beste/json/.github/FUNDING.yml
vendored
Normal file
2
vendor/beste/json/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github: jeromegamez
|
||||
tidelift: "packagist/beste/json"
|
||||
15
vendor/beste/json/.github/dependabot.yml
vendored
Normal file
15
vendor/beste/json/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
include: "scope"
|
||||
prefix: "github-actions"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependency"
|
||||
2
vendor/beste/json/.github/settings.yml
vendored
Normal file
2
vendor/beste/json/.github/settings.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# https://probot.github.io/apps/settings/
|
||||
_extends: beste/.github
|
||||
23
vendor/beste/json/.github/workflows/dependabot-auto-merge.yml
vendored
Normal file
23
vendor/beste/json/.github/workflows/dependabot-auto-merge.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: "Dependabot auto-merge"
|
||||
|
||||
on: [pull_request_target] # yamllint disable-line rule:truthy
|
||||
|
||||
permissions:
|
||||
contents: "write"
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
runs-on: "ubuntu-latest"
|
||||
if: "${{ github.actor == 'dependabot[bot]' }}"
|
||||
steps:
|
||||
- name: "Dependabot metadata"
|
||||
id: "metadata"
|
||||
uses: "dependabot/fetch-metadata@v2.4.0"
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: "Enable auto-merge for Dependabot PRs"
|
||||
if: "${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }}"
|
||||
run: "gh pr merge --auto --merge \"$PR_URL\""
|
||||
env:
|
||||
PR_URL: "${{github.event.pull_request.html_url}}"
|
||||
GITHUB_TOKEN: "${{secrets.GITHUB_TOKEN}}"
|
||||
80
vendor/beste/json/.github/workflows/tests.yml
vendored
Normal file
80
vendor/beste/json/.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- '.github/workflows/tests.yml'
|
||||
- 'composer.json'
|
||||
push:
|
||||
branches: ['main']
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- '.github/workflows/tests.yml'
|
||||
- 'composer.json'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: PHP ${{ matrix.php }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
include:
|
||||
- php: "8.5"
|
||||
composer-options: "--ignore-platform-reqs"
|
||||
dependencies: "highest"
|
||||
|
||||
env:
|
||||
extensions: json
|
||||
key: "cache-${{ matrix.php }}-${{ matrix.dependencies }}-v2" # can be any string, change to clear the extension cache.
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup cache environment
|
||||
id: extcache
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: ${{ env.extensions }}
|
||||
key: ${{ env.key }}
|
||||
|
||||
- name: Cache extensions
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.extcache.outputs.dir }}
|
||||
key: ${{ steps.extcache.outputs.key }}
|
||||
restore-keys: ${{ steps.extcache.outputs.key }}
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: ${{ env.extensions }}
|
||||
tools: composer, pecl
|
||||
coverage: xdebug
|
||||
env:
|
||||
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: "ramsey/composer-install@v3"
|
||||
|
||||
- name: Setup Problem Matchers
|
||||
run: |
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Run PHPStan
|
||||
run: vendor/bin/phpstan
|
||||
|
||||
- name: Run PHPUnit
|
||||
run: vendor/bin/phpunit --testdox --coverage-text
|
||||
44
vendor/beste/json/CHANGELOG.md
vendored
Normal file
44
vendor/beste/json/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# CHANGELOG
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 1.7.0 - 2025-09-12
|
||||
|
||||
* Added support for PHP 8.5
|
||||
|
||||
## 1.6.0 - 2025-04-07
|
||||
|
||||
* Use conditional PHPStan return type to correctly type hint an array when using `JSON::decode()` and
|
||||
`JSON::decodeFile()`
|
||||
|
||||
## 1.5.0 - 2024-12-19
|
||||
|
||||
* Remove requirement that a string must be non-empty
|
||||
|
||||
## 1.5.0 - 2024-08-17
|
||||
|
||||
* Added support for PHP 8.4
|
||||
|
||||
## 1.4.0 - 2023-11-30
|
||||
|
||||
* Restored support for PHP 8.1
|
||||
|
||||
## 1.3.0 - 2023-11-25
|
||||
|
||||
* Added support for PHP 8.3, dropped support for PHP 8.1
|
||||
|
||||
## 1.2.1 - 2022-12-19
|
||||
|
||||
Fixed symlinks not being properly resolved
|
||||
|
||||
## 1.2.0 - 2022-12-01
|
||||
|
||||
Added more checks when decoding JSON Files
|
||||
|
||||
## 1.1.0 - 2022-11-04
|
||||
|
||||
Dropped support for PHP <8.1
|
||||
|
||||
## 1.0.0 - 2022-02-12
|
||||
|
||||
Initial release
|
||||
21
vendor/beste/json/LICENSE
vendored
Normal file
21
vendor/beste/json/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Jérôme Gamez, https://github.com/beste <jerome@gamez.name>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
46
vendor/beste/json/README.md
vendored
Normal file
46
vendor/beste/json/README.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# JSON
|
||||
|
||||
[](https://packagist.org/packages/beste/json)
|
||||
[](https://packagist.org/packages/beste/json)
|
||||
[](https://github.com/beste/json/actions)
|
||||
[](https://discord.gg/Yacm7unBsr)
|
||||
[](https://github.com/sponsors/jeromegamez)
|
||||
|
||||
A simple helper to decode and encode JSON, including from files.
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
use Beste\Json;
|
||||
use UnexpectedValueException;
|
||||
|
||||
$object = Json::decode('{"key": "value"}');
|
||||
|
||||
$array = Json::decode('{"key": "value"}', $forceArray = true);
|
||||
|
||||
$object = Json::decodeFile('/path/to/file.json');
|
||||
|
||||
$json = Json::encode($object);
|
||||
|
||||
$prettyJson = Json::pretty($object);
|
||||
|
||||
// When something goes wring while decoding/encoding,
|
||||
// an `UnexpectedValueException` is thrown
|
||||
try {
|
||||
Json::decode('{]');
|
||||
} catch (UnexpectedValueException $e) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
composer require beste/json
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
```shell
|
||||
composer test
|
||||
```
|
||||
5
vendor/beste/json/SECURITY.md
vendored
Normal file
5
vendor/beste/json/SECURITY.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
||||
52
vendor/beste/json/composer.json
vendored
Normal file
52
vendor/beste/json/composer.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "beste/json",
|
||||
"type": "library",
|
||||
"description": "A simple JSON helper to decode and encode JSON",
|
||||
"keywords": ["json", "helper"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jérôme Gamez",
|
||||
"email": "jerome@gamez.name"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/phpstan": "^2.0.4",
|
||||
"phpstan/phpstan-phpunit": "^2.0.2",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.1",
|
||||
"phpunit/phpunit": "^10.4.2",
|
||||
"rector/rector": "^2.0.3"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Json.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Beste\\Json\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"analyse": [
|
||||
"XDEBUG_MODE=off vendor/bin/phpstan"
|
||||
],
|
||||
"analyze": "@analyse",
|
||||
"test": [
|
||||
"@analyse",
|
||||
"@test-units"
|
||||
],
|
||||
"test-units": "vendor/bin/phpunit"
|
||||
}
|
||||
}
|
||||
21
vendor/beste/json/phpunit.xml.dist
vendored
Normal file
21
vendor/beste/json/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Tests">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage ignoreDeprecatedCodeUnits="true"/>
|
||||
|
||||
<source>
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
89
vendor/beste/json/src/Json.php
vendored
Normal file
89
vendor/beste/json/src/Json.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste;
|
||||
|
||||
use JsonException;
|
||||
use SplFileInfo;
|
||||
use SplFileObject;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
|
||||
final class Json
|
||||
{
|
||||
private const ENCODE_DEFAULT = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
private const ENCODE_PRETTY = self::ENCODE_DEFAULT | JSON_PRETTY_PRINT;
|
||||
private const DECODE_DEFAULT = JSON_BIGINT_AS_STRING;
|
||||
|
||||
/**
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @return ($forceArray is true ? array<mixed> : mixed)
|
||||
*/
|
||||
public static function decode(string $json, ?bool $forceArray = null): mixed
|
||||
{
|
||||
$forceArray ??= false;
|
||||
$flags = $forceArray ? JSON_OBJECT_AS_ARRAY : 0;
|
||||
|
||||
try {
|
||||
return json_decode($json, $forceArray, 512, $flags | self::DECODE_DEFAULT | JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new UnexpectedValueException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $path
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @return ($forceArray is true ? array<mixed> : mixed)
|
||||
*/
|
||||
public static function decodeFile(string $path, ?bool $forceArray = null): mixed
|
||||
{
|
||||
if (!is_readable($path)) {
|
||||
throw new UnexpectedValueException("The file at '$path' is not readable");
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
throw new UnexpectedValueException("'$path' points to a directory");
|
||||
}
|
||||
|
||||
$contents = file_get_contents($path);
|
||||
|
||||
if ($contents === false) {
|
||||
throw new UnexpectedValueException("The file at '$path' is not readable");
|
||||
}
|
||||
|
||||
if ($contents === '') {
|
||||
throw new UnexpectedValueException("The file at '$path' is empty");
|
||||
}
|
||||
|
||||
return self::decode($contents, $forceArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public static function encode(mixed $data, ?int $options = null): string
|
||||
{
|
||||
$options ??= 0;
|
||||
|
||||
try {
|
||||
return json_encode($data, $options | self::ENCODE_DEFAULT | JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
throw new UnexpectedValueException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public static function pretty(mixed $value, ?int $options = null): string
|
||||
{
|
||||
$options ??= 0;
|
||||
|
||||
return self::encode($value, $options | self::ENCODE_PRETTY);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user