From cef981295ee19c9078ccbebbf4170e00bde15ba1 Mon Sep 17 00:00:00 2001 From: Craig Smith <craigsmith@Craigs-MBP-2.localdomain> Date: Tue, 14 Mar 2023 16:28:10 +1300 Subject: [PATCH] feat: enhanced date functionality Breaking-change: removed cdcarbondate facade, use the class directly instead --- .lando.yml | 26 ++++++++++++- composer.json | 4 +- src/CdCarbonDate.php | 58 ++++++++++++----------------- src/CdCarbonMixin.php | 8 ++-- src/Exceptions/RuntimeException.php | 44 ++++++++++++++++++++++ src/Facades/CdCarbonDate.php | 23 ------------ src/ServiceProvider.php | 6 +-- tests/DateHandlingTest.php | 36 +++++++++++++----- 8 files changed, 128 insertions(+), 77 deletions(-) create mode 100644 src/Exceptions/RuntimeException.php delete mode 100644 src/Facades/CdCarbonDate.php diff --git a/.lando.yml b/.lando.yml index 3fd188f..f172fe6 100644 --- a/.lando.yml +++ b/.lando.yml @@ -57,15 +57,37 @@ tooling: - composer phpstan all81: - service: appserver + service: php81 cmd: - rm -rf vendor composer.lock && composer install - composer phpunit - composer phpstan all80: - service: appserver + service: php80 cmd: - rm -rf vendor composer.lock && composer install - composer phpunit - composer phpstan + + lara8: + service: php81 + cmd: + - rm -rf vendor composer.lock + - composer require laravel/laravel:^8 + - composer install + - composer phpunit + - composer phpstan + # this is for removing a specific version + - composer remove laravel/laravel + + lara9: + service: php81 + cmd: + - rm -rf vendor composer.lock + - composer require laravel/laravel:^9 + - composer install + - composer phpunit + - composer phpstan + # this is for removing a specific version + - composer remove laravel/laravel diff --git a/composer.json b/composer.json index f7f1fc4..4febb9b 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,8 @@ ], "require": { "php": "^8.0", - "illuminate/support": "^8.5|^9.0|^10", - "illuminate/notifications": "^8.5|^9.0|^10.0" + "illuminate/notifications": "^8.5|^9.0|^10.0", + "illuminate/support": "^8.5|^9.0|^10" }, "require-dev": { "orchestra/testbench": "^6.0|^7.0|^8.0", diff --git a/src/CdCarbonDate.php b/src/CdCarbonDate.php index c8a1213..2622e85 100644 --- a/src/CdCarbonDate.php +++ b/src/CdCarbonDate.php @@ -1,60 +1,48 @@ <?php namespace CustomD\LaravelHelpers; +use DateTimeInterface; +use Carbon\CarbonImmutable; use \Illuminate\Support\Carbon; +use Carbon\Carbon as CarbonCarbon; +use Carbon\CarbonInterface; use Illuminate\Support\Facades\Date; -use DateTimeInterface; class CdCarbonDate { protected string $userTimezone; protected string $systemTimezone; + protected CarbonInterface $carbon; public function __construct(?string $userTimezone = null, ?string $systemTimezone = null) { $this->userTimezone = $userTimezone ?? config('request.user.timezone') ?? config('app.user_timezone') ?? config('app.timezone'); // @phpstan-ignore-line -- will be string $this->systemTimezone = $systemTimezone ?? config('app.timezone'); //@phpstan-ignore-line - timezone is string - } - - public function setUserTimezone(string $userTimezone): static - { - $this->userTimezone = $userTimezone; - return $this; - } - - public function getUserTimezone(): string - { - return $this->userTimezone; - } - public function setSystemTimezone(string $systemTimezone): static - { - $this->systemTimezone = $systemTimezone; - return $this; - } - - public function getSystemTimezone(): string - { - return $this->systemTimezone; - } + $this->carbon = (new CarbonImmutable()); - public function usersStartOfDay(DateTimeInterface|string|null $date = null): Carbon - { - return Date::parse($date ?? now(), $this->userTimezone)->setTimezone($this->userTimezone)->startOfDay()->setTimezone($this->systemTimezone); - } - - public function usersEndOfDay(DateTimeInterface|string|null $date = null): Carbon - { - return Date::parse($date ?? now(), $this->userTimezone)->setTimezone($this->userTimezone)->endOfDay()->setTimezone($this->systemTimezone); + $this->carbon->setUserTimezone(strval($this->userTimezone)) + ->setSystemTimezone(strval($this->systemTimezone)); } - public function toUsersTimezone(DateTimeInterface|string|null $date = null): Carbon + /** + * @param string $name + * @param array<mixed,mixed> $arguments + * @return mixed + */ + public function __call(string $name, array $arguments): mixed { - return Date::parse($date ?? now(), $this->systemTimezone)->setTimezone($this->userTimezone); + return $this->carbon->{$name}(...$arguments); } - public function toSystemTimezone(DateTimeInterface|string|null $date = null): Carbon + /** + * @param string $name + * @param array<mixed,mixed> $arguments + * @return mixed + */ + public static function __callStatic(string $name, array $arguments): mixed { - return Date::parse($date ?? now(), $this->systemTimezone)->setTimezone($this->systemTimezone); + $instance = new static(); //@phpstan-ignore-line + return $instance->{$name}(...$arguments); } } diff --git a/src/CdCarbonMixin.php b/src/CdCarbonMixin.php index 14be9ce..9a32469 100644 --- a/src/CdCarbonMixin.php +++ b/src/CdCarbonMixin.php @@ -24,8 +24,9 @@ class CdCarbonMixin { $mixin = $this; - return static function (string $timezone) use ($mixin) { + return function (string $timezone) use ($mixin) { $mixin->userTimezone = $timezone; + return $this; }; } @@ -42,8 +43,9 @@ class CdCarbonMixin { $mixin = $this; - return static function (string $timezone) use ($mixin) { + return function (string $timezone) use ($mixin) { $mixin->systemTimezone = $timezone; + return $this; }; } @@ -180,7 +182,7 @@ class CdCarbonMixin return static function ($time) { /** @var Carbon $date */ $date = self::this(); - return self::parse($time, $date->getUserTimezone()); + return $date->parse($time, $date->getUserTimezone()); }; } } diff --git a/src/Exceptions/RuntimeException.php b/src/Exceptions/RuntimeException.php new file mode 100644 index 0000000..f42bff9 --- /dev/null +++ b/src/Exceptions/RuntimeException.php @@ -0,0 +1,44 @@ +<?php +namespace CustomD\LaravelHelpers\Exceptions; + +use Illuminate\Http\JsonResponse; +use Throwable; +use RuntimeException as CoreException; + +class RuntimeException extends CoreException +{ + public int $statusCode = 500; + + public string $extra = ''; + + + public function __construct(string $message = "", string $extra = '', int $statusCode = 500, int $code = 0, Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + $this->extra = $extra; + $this->statusCode = $statusCode; + } + + + public static function err404(string $message = "Not Found", string $extra = ''): static + { + //@phpstan-ignore-next-line + return new static($message, $extra, 404); + } + + + public static function err500(string $message = "Internal Server Error", string $extra = ''): static + { + //@phpstan-ignore-next-line + return new static($message, $extra, 500); + } + + public function render(): JsonResponse + { + return new JsonResponse([ + 'message' => $this->message, + 'extra' => $this->extra, + 'type' => __CLASS__, + ], $this->statusCode); + } +} diff --git a/src/Facades/CdCarbonDate.php b/src/Facades/CdCarbonDate.php deleted file mode 100644 index e60831e..0000000 --- a/src/Facades/CdCarbonDate.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -namespace CustomD\LaravelHelpers\Facades; - -use Illuminate\Support\Facades\Facade; - -/** - * @method static \CustomD\LaravelHelpers\CdCarbonDate setUserTimezone(string $userTimezone) - * @method static string getUserTimezone() - * @method static \CustomD\LaravelHelpers\CdCarbonDate setSystemTimezone(string $systemTimezone) - * @method static string getSystemTimezone() - * @method static \Illuminate\Support\Carbon usersStartOfDay() - * @method static \Illuminate\Support\Carbon usersEndOfDay() - * @method static \Illuminate\Support\Carbon toUsersTimezone() - * @method static \Illuminate\Support\Carbon toSystemTimezone() - */ -class CdCarbonDate extends Facade -{ - - protected static function getFacadeAccessor() - { - return 'cd-carbon-date'; - } -} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 457bf3a..d83b508 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -4,6 +4,7 @@ namespace CustomD\LaravelHelpers; use Closure; use Carbon\Carbon; +use Carbon\CarbonImmutable; use Illuminate\Support\Str; use Illuminate\Database\Query\Builder; use Illuminate\Database\Eloquent\Model; @@ -18,10 +19,9 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider public function register() { - $this->app->bind('cd-carbon-date', function ($app) { - return new CdCarbonDate(); - }); + Carbon::mixin(new CdCarbonMixin()); + CarbonImmutable::mixin(new CdCarbonMixin()); } diff --git a/tests/DateHandlingTest.php b/tests/DateHandlingTest.php index 592002f..6a3298e 100644 --- a/tests/DateHandlingTest.php +++ b/tests/DateHandlingTest.php @@ -3,7 +3,8 @@ namespace CustomD\LaravelHelpers\Tests; use Carbon\Carbon; -use CustomD\LaravelHelpers\Facades\CdCarbonDate; +use Carbon\CarbonImmutable; +use CustomD\LaravelHelpers\CdCarbonDate; use Mockery; use Mockery\MockInterface; use Illuminate\Http\Request; @@ -13,6 +14,7 @@ use CustomD\LaravelHelpers\ServiceProvider; use CustomD\LaravelHelpers\Facades\LaravelHelpers; use CustomD\LaravelHelpers\Http\Middleware\UserTimeZone; use CustomD\LaravelHelpers\Tests\ExecutableAction; +use Illuminate\Support\Carbon as SupportCarbon; class DateHandlingTest extends TestCase { @@ -35,23 +37,39 @@ class DateHandlingTest extends TestCase $nzDate = '2023-01-05T22:04:00.000Z'; //equiv to 2023-01-06 11:04:00 AM NZ Carbon::setTestNow($nzDate); + CarbonImmutable::setTestNow($nzDate); + //asserting carbon dates $this->assertEquals("Thu Jan 05 2023 22:04:00 GMT+0000", now()->toString()); - $this->assertEquals("Fri Jan 06 2023 11:04:00 GMT+1300", CdCarbonDate::toUsersTimezone(now())->toString()); $this->assertEquals("Fri Jan 06 2023 11:04:00 GMT+1300", now()->toUsersTimezone()->toString()); $this->assertEquals("Fri Jan 06 2023 11:04:00 GMT+1300", Carbon::toUsersTimezone()->toString()); - - $this->assertEquals("Thu Jan 05 2023 11:00:00 GMT+0000", CdCarbonDate::usersStartOfDay()->toString()); $this->assertEquals("Thu Jan 05 2023 11:00:00 GMT+0000", Carbon::usersStartOfDay()->toString()); $this->assertEquals("Thu Jan 05 2023 11:00:00 GMT+0000", now()->usersStartOfDay()->toString()); - - $this->assertEquals("Sat Jan 07 2023 10:59:59 GMT+0000", CdCarbonDate::usersEndOfDay('2023-01-07 23:55:00')->toString()); $this->assertEquals("Sat Jan 07 2023 10:59:59 GMT+0000", Carbon::parseWithTz('2023-01-07 23:55:00')->usersEndOfDay()->toString()); - - $this->assertEquals("Sat Dec 31 2022 11:00:00 GMT+0000", CdCarbonDate::usersStartOfDay('2023-01-01T02:04:00.000Z')->toString()); $this->assertEquals("Sat Dec 31 2022 11:00:00 GMT+0000", Carbon::parseWithTz('2023-01-01T02:04:00.000Z')->usersStartOfDay()->toString()); - $this->assertEquals("Fri Jan 06 2023 10:59:59 GMT+0000", now()->usersEndOfDay()->toString()); + + //make sure the factory returns a new instance each time + $customdDate1 = CdCarbonDate::toUsersTimezone(now()->toString()); + $customdDate2 = CdCarbonDate::setUserTimezone('Africa/Johannesburg')->toUsersTimezone(now()->toString()); + + $this->assertNotEquals($customdDate1->toString(), $customdDate2->toString()); + + $this->assertEquals("Fri Jan 06 2023 11:04:00 GMT+1300", CdCarbonDate::toUsersTimezone(now())->toString()); + $this->assertEquals("Thu Jan 05 2023 11:00:00 GMT+0000", CdCarbonDate::usersStartOfDay()->toString()); + $this->assertEquals("Tue Jan 10 2023 10:59:59 GMT+0000", CdCarbonDate::parse('2023-01-09 23:55:00')->usersEndOfDay()->toString()); + $this->assertEquals("Sat Dec 31 2022 11:00:00 GMT+0000", CdCarbonDate::parse('2023-01-01T02:04:00.000Z')->usersStartOfDay()->toString()); + } + + public function testMultipleCarbonInstances() + { + Config::set('app.user_timezone', 'Pacific/Auckland'); + $nzDate = '2023-01-05T22:04:00.000Z'; //equiv to 2023-01-06 11:04:00 AM NZ + Carbon::setTestNow($nzDate); + + $custom = CdCarbonDate::setUserTimezone('Africa/Johannesburg'); + + $this->assertNotEquals(now()->toUsersTimezone()->toString(), $custom->toUsersTimezone(now())->toString()); } public function testSetsViaMiddleware() -- GitLab