├── .github ├── FUNDING.yml └── workflows │ └── php.yml ├── src ├── LaradateServiceProvider.php ├── DateRouteBind.php └── Http │ └── Middleware │ └── ContainDate.php ├── LICENSE.md ├── composer.json └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # Help me support this package 2 | 3 | ko_fi: DarkGhostHunter 4 | custom: ['https://paypal.me/darkghosthunter'] 5 | -------------------------------------------------------------------------------- /src/LaradateServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton(DateRouteBind::class, static function($app) : DateRouteBind { 25 | return new DateRouteBind($app[DateFactory::class]); 26 | }); 27 | 28 | $this->app->afterResolving('router', static function (Router $router, Application $app): void { 29 | $router->bind('date', [$app->make(DateRouteBind::class), 'date']); 30 | 31 | $router->aliasMiddleware('date', Http\Middleware\ContainDate::class); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Italo Israel Baeza Cabrera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/DateRouteBind.php: -------------------------------------------------------------------------------- 1 | factory->createFromFormat($route->bindingFieldFor('date') ?? '!Y-m-d', $value); 38 | } catch (Exception $e) { 39 | throw new HttpException(404, null, $e); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Http/Middleware/ContainDate.php: -------------------------------------------------------------------------------- 1 | route()->parameter('date')) { 27 | abort_unless($this->isDateBetween($date, $min, $max), 404); 28 | } 29 | 30 | return $next($request); 31 | } 32 | 33 | /** 34 | * Checks if the date is between two dates. 35 | * 36 | * @param \DateTimeInterface $date 37 | * @param string|null $min 38 | * @param string|null $max 39 | * 40 | * @return bool 41 | * @throws \Exception 42 | */ 43 | protected function isDateBetween(DateTimeInterface $date, ?string $min, ?string $max): bool 44 | { 45 | if (!$min && !$max) { 46 | throw new RuntimeException("No minimum or maximum dates to compare [{$date->format('Y-m-d H:i:s')}]."); 47 | } 48 | 49 | if ($min && $date < new DateTime($min)) { 50 | return false; 51 | } 52 | 53 | if ($max && $date > new DateTime($max)) { 54 | return false; 55 | } 56 | 57 | return true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darkghosthunter/laradate", 3 | "description": "Route bind a date into a Carbon (or anything you want)", 4 | "keywords": [ 5 | "darkghosthunter", 6 | "laralerts", 7 | "alerts", 8 | "notifications", 9 | "flash", 10 | "session", 11 | "laravel" 12 | ], 13 | "homepage": "https://github.com/darkghosthunter/laralerts", 14 | "license": "MIT", 15 | "type": "library", 16 | "minimum-stability": "dev", 17 | "prefer-stable": true, 18 | "authors": [ 19 | { 20 | "name": "Italo Israel Baeza Cabrera", 21 | "email": "darkghosthunter@gmail.com", 22 | "role": "Developer" 23 | } 24 | ], 25 | "require": { 26 | "php": "^8.0", 27 | "ext-json": "*", 28 | "illuminate/support": "^8.0", 29 | "illuminate/routing": "^8.0", 30 | "illuminate/http": "^8.0", 31 | "nesbot/carbon": ">=2.51.1" 32 | }, 33 | "require-dev": { 34 | "orchestra/testbench": "^6.19", 35 | "mockery/mockery": "^1.4.3", 36 | "phpunit/phpunit": "^9.5.8" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "DarkGhostHunter\\Laradate\\": "src/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Tests\\": "tests/" 46 | } 47 | }, 48 | "scripts": { 49 | "test": "vendor/bin/phpunit --coverage-clover build/logs/clover.xml", 50 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 51 | }, 52 | "config": { 53 | "sort-packages": true 54 | }, 55 | "extra": { 56 | "laravel": { 57 | "providers": [ 58 | "DarkGhostHunter\\Laradate\\LaradateServiceProvider" 59 | ] 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: true 13 | matrix: 14 | php: [8.0] 15 | laravel: [8.*] 16 | dependency-version: [prefer-lowest, prefer-stable] 17 | include: 18 | - laravel: 8.* 19 | testbench: ^6.17 20 | 21 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }} 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v2 26 | 27 | - name: Setup PHP 28 | uses: shivammathur/setup-php@v2 29 | with: 30 | php-version: ${{ matrix.php }} 31 | extensions: mbstring, intl 32 | coverage: xdebug 33 | 34 | - name: Cache dependencies 35 | uses: actions/cache@v2 36 | with: 37 | path: ~/.composer/cache/files 38 | key: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 39 | restore-keys: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer- 40 | 41 | - name: Install dependencies 42 | run: | 43 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-progress --no-update 44 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-suggest 45 | 46 | - name: Run Tests 47 | run: composer run-script test 48 | 49 | - name: Upload Coverage to Coveralls 50 | env: 51 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | COVERALLS_SERVICE_NAME: github 53 | run: | 54 | rm -rf composer.* vendor/ 55 | composer require php-coveralls/php-coveralls 56 | vendor/bin/php-coveralls 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Aron Visuals - Unsplash (UL) #BXOXnQ26B7o](https://images.unsplash.com/photo-1501139083538-0139583c060f?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1200&h=400&q=80) 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/darkghosthunter/laradate/v/stable)](https://packagist.org/packages/darkghosthunter/laradate) [![License](https://poser.pugx.org/darkghosthunter/laradate/license)](https://packagist.org/packages/darkghosthunter/laradate) ![](https://img.shields.io/packagist/php-v/darkghosthunter/laradate.svg) ![](https://github.com/DarkGhostHunter/Laradate/workflows/PHP%20Composer/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/Laradate/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/Laradate?branch=master) [![Laravel Octane Compatible](https://img.shields.io/badge/Laravel%20Octane-Compatible-success?style=flat&logo=laravel)](https://github.com/laravel/octane) [![Laravel Jetstream Compatible](https://img.shields.io/badge/Laravel%20Jetstream-Compatible-success?style=flat&logo=laravel)](https://jetstream.laravel.com/) 4 | 5 | # Laradate 6 | 7 | Parse a date from the URL, receive it as a `Carbon` instance in your controller. 8 | 9 | ## Requirements 10 | 11 | * Laravel 8.x or later 12 | * PHP 8.0 or later. 13 | 14 | > For older versions support, consider helping by sponsoring or donating. 15 | 16 | ## Installation 17 | 18 | You can install the package via composer: 19 | 20 | ```bash 21 | composer require darkghosthunter/laradate 22 | ``` 23 | 24 | ## Usage 25 | 26 | Simply set the `date` parameter to any route. In your controller, you will get a `Carbon` instance if the name of the variable is `$date`. 27 | 28 | ```php 29 | use Illuminate\Support\Facades\Route; 30 | use Illuminate\Support\Carbon; 31 | 32 | Route::get('matches/{date}', function (Carbon $date) { 33 | return $date; 34 | }); 35 | ``` 36 | 37 | > A date must be formatted as `YYYY-MM-DD` to reach the route, otherwise it won't be found. 38 | 39 | Behind the scenes, Laradate will use the `DateFactory`, which is the default factory in your application, to create instances of `DateTimeInterface`. By default, your application uses the Carbon library. 40 | 41 | > If the datetime cannot be parsed, the route will return HTTP 404. 42 | 43 | ### Using formats 44 | 45 | You can also use custom formatting for your routes with `{date:format}`. The format follows the same [Datetime formats](https://php.net/manual/datetime.createfromformat.php). If the string doesn't follow the format, the route will return an HTTP 404. 46 | 47 | ```php 48 | use Illuminate\Support\Facades\Route; 49 | use Illuminate\Support\Carbon; 50 | 51 | // birthdays/2015_07_04 52 | Route::get('birthdays/{date:Y_m_d}', function (Carbon $date) { 53 | return $date; 54 | }); 55 | ``` 56 | 57 | > Because of limitations of Laravel Router parameters for bindings, use underscore `_` as separator while using formats. 58 | 59 | ### Date between middleware 60 | 61 | To avoid having to fallback to the Laravel Validator inside the controller, you can use the `date` middleware which accepts a minimum, maximum, or both, dates to compare (inclusive). If the date is not inside the dates, an HTTP 404 code will be returned. 62 | 63 | Since the dates are passed to `DateTime`, you can use words like `today 00:00` or `3 months 23:59:59` for relative dates. 64 | 65 | ```php 66 | use Illuminate\Http\Request; 67 | use Illuminate\Support\Facades\Route; 68 | 69 | Route::post('birthdays/{date}', function (Request $request, Carbon $date) { 70 | // ... 71 | })->middleware('date:today 00:00,3 months 23:59:59'); 72 | ``` 73 | 74 | ## Security 75 | 76 | If you discover any security related issues, please email darkghosthunter@gmail.com instead of using the issue tracker. 77 | 78 | ## License 79 | 80 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 81 | --------------------------------------------------------------------------------