├── .editorconfig ├── .gitattributes.dist ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── check-links.yml │ ├── dependabot-auto-merge.yml │ ├── php-cs-fixer.yml │ ├── phpstan.yml │ ├── tests.yml │ └── update-changelog.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── last-modified.php ├── docs └── images │ ├── abordage-laravel-last-modified-cover-rounded.png │ └── check-last-modified-rounded.png ├── phpstan-baseline.neon ├── phpstan.neon.dist ├── phpunit.xml.dist ├── src ├── Facades │ └── LastModified.php ├── LastModified.php ├── LastModifiedServiceProvider.php └── Middleware │ └── LastModifiedHandling.php └── tests └── LastModifiedHandlingTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.gitattributes.dist: -------------------------------------------------------------------------------- 1 | # Ignore all test and documentation with "export-ignore". 2 | .editorconfig export-ignore 3 | .gitattributes export-ignore 4 | .github export-ignore 5 | .gitignore export-ignore 6 | .php-cs-fixer.cache export-ignore 7 | .php-cs-fixer.php export-ignore 8 | /art export-ignore 9 | /docs export-ignore 10 | /tests export-ignore 11 | UPGRADING.md export-ignore 12 | testbench.yaml export-ignore 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a general package issue. Filling in the issue template is mandatory, issues without it will be closed. 3 | title: "[Bug]: " 4 | labels: [ bug ] 5 | body: 6 | - type: checkboxes 7 | id: terms 8 | attributes: 9 | label: Is the bug applicable and reproducible to the latest version of the package and hasn't it been reported before? 10 | options: 11 | - label: Yes, it's still reproducible 12 | required: true 13 | - type: input 14 | attributes: 15 | label: What version of Package are you using? 16 | description: 'For example: 1.2.0' 17 | validations: 18 | required: true 19 | - type: input 20 | attributes: 21 | label: What version of Laravel are you using? 22 | description: 'For example: 9.52.0' 23 | validations: 24 | required: true 25 | - type: input 26 | attributes: 27 | label: What version of PHP are you using? 28 | description: 'For example: 8.1.0' 29 | validations: 30 | required: true 31 | - type: textarea 32 | attributes: 33 | label: Describe your issue 34 | description: Describe the problem you're seeing, Please be short, but concise. 35 | validations: 36 | required: true 37 | - type: textarea 38 | attributes: 39 | label: How can the issue be reproduced? 40 | description: Please provide easy-to-reproduce steps (repository, simple code example, failing unit test). Please don't paste your entire code, but create a reproducible scenario that can be tested using a simple User model in a blank Laravel installation. 41 | validations: 42 | required: true 43 | - type: textarea 44 | attributes: 45 | label: What should be the expected behaviour? 46 | description: Please describe what the expected outcome should be. Any suggestions to what is wrong? 47 | validations: 48 | required: true 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/abordage/laravel-last-modified/discussions/new?category=q-a 5 | about: Ask the community for help 6 | - name: Request a feature 7 | url: https://github.com/abordage/laravel-last-modified/discussions/new?category=ideas 8 | about: Share ideas for new features 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion. 2 | 3 | 4 | > 💡 Please take note of our [contributing guidelines](https://github.com/abordage/.github/blob/master/CONTRIBUTING.md) 5 | 6 | 1. Why should it be added? What are the benefits of this change? 7 | 2. Does it contain multiple, unrelated changes? Please separate the PRs out. 8 | 3. Does it include tests, if possible? 9 | 4. Any drawbacks? Possible breaking changes? 10 | 11 | **Mark the following tasks as done:** 12 | - [ ] Checked the codebase to ensure that your feature doesn't already exist. 13 | - [ ] Take note of the contributing guidelines. 14 | - [ ] Checked the pull requests to ensure that another person hasn't already submitted a fix. 15 | - [ ] Added tests to ensure against regression. 16 | - [ ] Updated the changelog 17 | 18 | ### Thanks for contributing! 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | labels: 12 | - "dependencies" -------------------------------------------------------------------------------- /.github/workflows/check-links.yml: -------------------------------------------------------------------------------- 1 | name: Check Links 2 | 3 | on: 4 | repository_dispatch: 5 | workflow_dispatch: 6 | schedule: 7 | - cron: "30 3 * * 1" 8 | 9 | jobs: 10 | linkChecker: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: Link Checker 16 | id: lychee 17 | uses: lycheeverse/lychee-action@v1.10.0 18 | with: 19 | args: --verbose --no-progress --exclude-mail './**/*.md' './**/*.html' 20 | env: 21 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 22 | 23 | - name: Create Issue From File 24 | if: steps.lychee.outputs.exit_code != 0 25 | uses: peter-evans/create-issue-from-file@v5 26 | with: 27 | title: Link Checker Report 28 | content-filepath: ./lychee/out.md 29 | labels: report, automated issue 30 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | 3 | on: pull_request_target 4 | 5 | permissions: 6 | pull-requests: write 7 | contents: write 8 | 9 | jobs: 10 | dependabot: 11 | runs-on: ubuntu-latest 12 | if: ${{ github.actor == 'dependabot[bot]' }} 13 | steps: 14 | 15 | - name: Dependabot metadata 16 | id: metadata 17 | uses: dependabot/fetch-metadata@v2.2.0 18 | with: 19 | github-token: "${{ secrets.GITHUB_TOKEN }}" 20 | 21 | - name: Auto-merge Dependabot PRs for semver-minor updates 22 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} 23 | run: gh pr merge --auto --merge "$PR_URL" 24 | env: 25 | PR_URL: ${{github.event.pull_request.html_url}} 26 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 27 | 28 | - name: Auto-merge Dependabot PRs for semver-patch updates 29 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} 30 | run: gh pr merge --auto --merge "$PR_URL" 31 | env: 32 | PR_URL: ${{github.event.pull_request.html_url}} 33 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 34 | -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: PHP CS Fixer 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v4 12 | with: 13 | ref: ${{ github.head_ref }} 14 | 15 | - name: Run PHP CS Fixer 16 | uses: docker://oskarstark/php-cs-fixer-ga 17 | with: 18 | args: --config=.php-cs-fixer.dist.php 19 | 20 | - name: Commit changes 21 | uses: stefanzweifel/git-auto-commit-action@v5 22 | with: 23 | commit_message: fix styling 24 | -------------------------------------------------------------------------------- /.github/workflows/phpstan.yml: -------------------------------------------------------------------------------- 1 | name: PHPStan 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - '**.php' 8 | - 'phpstan.neon.dist' 9 | pull_request: 10 | paths: 11 | - '**.php' 12 | - 'phpstan.neon.dist' 13 | 14 | jobs: 15 | phpstan: 16 | name: phpstan 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Setup PHP 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: '8.0' 25 | coverage: none 26 | 27 | - name: Install composer dependencies 28 | uses: ramsey/composer-install@v3 29 | 30 | - name: Run PHPStan 31 | run: ./vendor/bin/phpstan --error-format=github 32 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | stability: [ prefer-stable ] 13 | os: [ ubuntu-latest ] 14 | php: [ 7.4, 8.0, 8.1, 8.2, 8.3 ] 15 | laravel: [ 8.*, 9.*, 10.*, 11.* ] 16 | include: 17 | - laravel: 8.* 18 | testbench: ^6.0 19 | - laravel: 9.* 20 | testbench: ^7.0 21 | - laravel: 10.* 22 | testbench: ^8.0 23 | - laravel: 11.* 24 | testbench: ^9.0 25 | exclude: 26 | - php: 7.4 27 | laravel: 9.* 28 | - php: 7.4 29 | laravel: 10.* 30 | - php: 7.4 31 | laravel: 11.* 32 | - php: 8.0 33 | laravel: 10.* 34 | - php: 8.0 35 | laravel: 11.* 36 | - php: 8.1 37 | laravel: 11.* 38 | - php: 8.2 39 | laravel: 8.* 40 | - php: 8.3 41 | laravel: 8.* 42 | - php: 8.3 43 | laravel: 9.* 44 | 45 | name: Laravel ${{ matrix.laravel }} on PHP ${{ matrix.php }} 46 | 47 | steps: 48 | - name: Checkout code 49 | uses: actions/checkout@v4 50 | 51 | - name: Setup PHP 52 | uses: shivammathur/setup-php@v2 53 | with: 54 | php-version: ${{ matrix.php }} 55 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo 56 | tools: composer:v2 57 | coverage: none 58 | 59 | - name: Install dependencies 60 | run: | 61 | composer require "laravel/framework=${{ matrix.laravel }}" "orchestra/testbench=${{ matrix.testbench }}" --no-update 62 | composer update --prefer-dist --no-interaction --no-progress 63 | - name: Run tests 64 | run: vendor/bin/phpunit 65 | -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | with: 15 | ref: ${{ github.event.release.target_commitish }} 16 | 17 | - name: Update Changelog 18 | uses: stefanzweifel/changelog-updater-action@v1 19 | with: 20 | latest-version: ${{ github.event.release.tag_name }} 21 | release-notes: ${{ github.event.release.body }} 22 | 23 | - name: Commit updated CHANGELOG 24 | uses: stefanzweifel/git-auto-commit-action@v5 25 | with: 26 | branch: ${{ github.event.release.target_commitish }} 27 | commit_message: Update CHANGELOG 28 | file_pattern: CHANGELOG.md 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .php-cs-fixer.cache 2 | .php-cs-fixer.php 3 | .phpunit.result.cache 4 | .vscode 5 | /.idea 6 | /build 7 | /coverage 8 | /node_modules 9 | /vendor 10 | composer.lock 11 | npm-debug.log 12 | phpstan.neon 13 | phpunit.xml 14 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in([ 7 | __DIR__ . '/config', 8 | __DIR__ . '/src', 9 | __DIR__ . '/tests', 10 | ]) 11 | ->name('*.php') 12 | ->notName('*.blade.php') 13 | ->ignoreDotFiles(true) 14 | ->ignoreVCS(true); 15 | 16 | return (new PhpCsFixer\Config()) 17 | ->setRules([ 18 | '@PSR12' => true, 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 21 | 'no_unused_imports' => true, 22 | 'not_operator_with_successor_space' => false, 23 | 'trailing_comma_in_multiline' => false, 24 | 'phpdoc_scalar' => true, 25 | 'unary_operator_spaces' => true, 26 | 'binary_operator_spaces' => true, 27 | 'blank_line_before_statement' => [ 28 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 29 | ], 30 | 'phpdoc_single_line_var_spacing' => true, 31 | 'phpdoc_var_without_name' => true, 32 | 'class_attributes_separation' => [ 33 | 'elements' => [ 34 | 'method' => 'one', 35 | ], 36 | ], 37 | 'method_argument_space' => [ 38 | 'on_multiline' => 'ensure_fully_multiline', 39 | 'keep_multiple_spaces_after_comma' => true, 40 | ], 41 | 'single_trait_insert_per_statement' => true, 42 | ]) 43 | ->setFinder($finder); 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-last-modified` will be documented in this file. 4 | 5 | ## 0.2.1 - 2024-03-23 6 | 7 | ### What's Changed 8 | 9 | * Bump lycheeverse/lychee-action from 1.5.4 to 1.6.1 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/13 10 | * Bump lycheeverse/lychee-action from 1.6.1 to 1.7.0 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/15 11 | * Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/16 12 | * Bump lycheeverse/lychee-action from 1.7.0 to 1.8.0 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/17 13 | * Bump dependabot/fetch-metadata from 1.4.0 to 1.5.0 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/18 14 | * Bump dependabot/fetch-metadata from 1.5.0 to 1.5.1 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/19 15 | * Bump dependabot/fetch-metadata from 1.5.1 to 1.6.0 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/20 16 | * Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/21 17 | * Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/22 18 | * Bump lycheeverse/lychee-action from 1.8.0 to 1.9.1 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/23 19 | * Bump lycheeverse/lychee-action from 1.9.1 to 1.9.3 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/24 20 | * Bump ramsey/composer-install from 2 to 3 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/26 21 | * Bump peter-evans/create-issue-from-file from 4 to 5 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/25 22 | * Laravel 11 support by @abordage in https://github.com/abordage/laravel-last-modified/pull/27 23 | 24 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.2.0...0.2.1 25 | 26 | ## 0.2.0 - 2023-02-25 27 | 28 | ### What's Changed 29 | 30 | - Laravel 10 support by @abordage in https://github.com/abordage/laravel-last-modified/pull/12 31 | - Bump dependabot/fetch-metadata from 1.3.1 to 1.3.3 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/2 32 | - Bump lycheeverse/lychee-action from 1.5.0 to 1.5.1 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/3 33 | - Bump dependabot/fetch-metadata from 1.3.3 to 1.3.4 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/7 34 | - Bump lycheeverse/lychee-action from 1.5.1 to 1.5.2 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/8 35 | - Bump dependabot/fetch-metadata from 1.3.4 to 1.3.5 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/9 36 | - Bump lycheeverse/lychee-action from 1.5.2 to 1.5.4 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/10 37 | - Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/abordage/laravel-last-modified/pull/11 38 | 39 | ### New Contributors 40 | 41 | - @dependabot made their first contribution in https://github.com/abordage/laravel-last-modified/pull/2 42 | 43 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.1.4...0.2.0 44 | 45 | ## 0.1.4 - 2022-06-21 46 | 47 | ### What's Changed 48 | 49 | - update docs by @abordage in https://github.com/abordage/laravel-last-modified/pull/1 50 | 51 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.1.3...0.1.4 52 | 53 | ## 0.1.3 - 2022-06-12 54 | 55 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.1.2...0.1.3 56 | 57 | ## 0.1.2 - 2022-06-11 58 | 59 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.1.1...0.1.2 60 | 61 | ## 0.1.1 - 2022-06-10 62 | 63 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/compare/0.1.0...0.1.1 64 | 65 | ## 0.1.0 - 2022-06-10 66 | 67 | **Full Changelog**: https://github.com/abordage/laravel-last-modified/commits/0.1.0 68 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) abordage 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Last-Modified / 304 Not Modified Handler for Laravel 4 | 5 | Easily setting the `Last-Modified` header and `304 Not Modified` response code. 6 | 7 |

8 | 9 | 10 | Packagist Version 11 | 12 | 13 | 14 | GitHub Tests Status 15 | 16 | 17 | 18 | GitHub Code Style Status 19 | 20 | 21 | 22 | PHP Version Support 23 | 24 | 25 | 26 | License 27 | 28 | 29 |

30 | 31 | 32 | ## Requirements 33 | - PHP 7.4 - 8.3 34 | - Laravel 8.x - 11.x 35 | 36 | ## Installation 37 | 38 | You can install the package via composer: 39 | 40 | ```bash 41 | composer require abordage/laravel-last-modified 42 | ``` 43 | 44 | Optionally, you can publish the config file with: 45 | 46 | ```bash 47 | php artisan vendor:publish --tag="last-modified-config" 48 | ``` 49 | ## Usage 50 | The setup is very simple and consists of two steps: 51 | 52 | ### Registering middleware 53 | 54 | ```php 55 | // in app/Http/Kernel.php 56 | 57 | protected $middleware = [ 58 | 'web' => [ 59 | // other middleware 60 | 61 | \Abordage\LastModified\Middleware\LastModifiedHandling::class, 62 | ], 63 | ]; 64 | ``` 65 | 66 | ### Set Last Update Date in your Controller 67 | 68 | ```php 69 | updated_at); 83 | 84 | return view('posts.show', ['post' => $post]); 85 | } 86 | } 87 | ``` 88 | It's all. Now you can check the headers. 89 | 90 | ## How to check headers 91 | 92 | You can check headers in the browser console under the `Network` tab (make sure `Disable Cache` is off) 93 | 94 | **or** 95 | 96 | using https://last-modified.com/en 97 | 98 |

99 | Check Last-Modified 100 |

101 | 102 | ## Testing 103 | 104 | ```bash 105 | composer test:all 106 | ``` 107 | 108 | or 109 | 110 | ```bash 111 | composer test:phpunit 112 | composer test:phpstan 113 | composer test:phpcsf 114 | ``` 115 | 116 | or see https://github.com/abordage/laravel-last-modified/actions/workflows/tests.yml 117 | 118 | ## Feedback 119 | 120 | If you have any feedback, comments or suggestions, please feel free to open an issue within this repository. 121 | 122 | ## Contributing 123 | 124 | Please see [CONTRIBUTING](https://github.com/abordage/.github/blob/master/CONTRIBUTING.md) for details. 125 | 126 | ## Credits 127 | 128 | - [Pavel Bychko](https://github.com/abordage) 129 | - [All Contributors](https://github.com/abordage/laravel-last-modified/graphs/contributors) 130 | 131 | ## License 132 | 133 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 134 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "abordage/laravel-last-modified", 3 | "description": "Setting the Last-Modified header and 304 Not Modified response code if the page hasn't changed since the last visit", 4 | "license": "MIT", 5 | "keywords": [ 6 | "304 Not Modified", 7 | "Last-Modified", 8 | "If-Modified-Since", 9 | "Laravel Last-Modified", 10 | "Laravel 304" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Pavel Bychko", 15 | "email": "box@abordage.dev", 16 | "role": "Developer" 17 | } 18 | ], 19 | "homepage": "https://github.com/abordage/laravel-last-modified", 20 | "require": { 21 | "php": ">=7.4", 22 | "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0" 23 | }, 24 | "require-dev": { 25 | "friendsofphp/php-cs-fixer": "^3.0", 26 | "nunomaduro/collision": "^5.0 || ^6.0 || ^7.0 || ^8.0", 27 | "nunomaduro/larastan": "^1.0 || ^2.0", 28 | "orchestra/testbench": "^6.0 || ^7.0 || ^8.0 || ^9.0", 29 | "phpunit/phpunit": "^9.5 || ^10.0" 30 | }, 31 | "minimum-stability": "stable", 32 | "prefer-stable": true, 33 | "autoload": { 34 | "psr-4": { 35 | "Abordage\\LastModified\\": "src" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Abordage\\LastModified\\Tests\\": "tests" 41 | } 42 | }, 43 | "config": { 44 | "sort-packages": true 45 | }, 46 | "extra": { 47 | "laravel": { 48 | "aliases": { 49 | "LastModified": "Abordage\\LastModified\\Facades\\LastModified" 50 | }, 51 | "providers": [ 52 | "Abordage\\LastModified\\LastModifiedServiceProvider" 53 | ] 54 | } 55 | }, 56 | "scripts": { 57 | "phpcsf": "vendor/bin/php-cs-fixer fix --diff", 58 | "phpstan:generate-baseline": "vendor/bin/phpstan --generate-baseline", 59 | "test:all": [ 60 | "@test:phpcsf", 61 | "@test:phpstan", 62 | "@test:phpunit" 63 | ], 64 | "test:phpcsf": "vendor/bin/php-cs-fixer fix --dry-run", 65 | "test:phpstan": "vendor/bin/phpstan analyse", 66 | "test:phpunit": "vendor/bin/phpunit --colors=always" 67 | }, 68 | "scripts-descriptions": { 69 | "phpcsf": "Run PHP-CS-Fixer fix", 70 | "phpstan:generate-baseline": "Generate baseline for PHPStan", 71 | "test:all": "Run all code analysis and tests", 72 | "test:phpcsf": "Run PHP-CS-Fixer test", 73 | "test:phpstan": "Run PHPStan", 74 | "test:phpunit": "Run PHPUnit" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /config/last-modified.php: -------------------------------------------------------------------------------- 1 | (bool)env('LAST_MODIFIED_HEADER', true), 5 | ]; 6 | -------------------------------------------------------------------------------- /docs/images/abordage-laravel-last-modified-cover-rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abordage/laravel-last-modified/c3529b7009d3e5ad4f525655eaba51cb8ef7f399/docs/images/abordage-laravel-last-modified-cover-rounded.png -------------------------------------------------------------------------------- /docs/images/check-last-modified-rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abordage/laravel-last-modified/c3529b7009d3e5ad4f525655eaba51cb8ef7f399/docs/images/check-last-modified-rounded.png -------------------------------------------------------------------------------- /phpstan-baseline.neon: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abordage/laravel-last-modified/c3529b7009d3e5ad4f525655eaba51cb8ef7f399/phpstan-baseline.neon -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | includes: 2 | - phpstan-baseline.neon 3 | - ./vendor/nunomaduro/larastan/extension.neon 4 | 5 | parameters: 6 | 7 | paths: 8 | - src 9 | - tests 10 | - config 11 | 12 | # The level 9 is the highest level 13 | level: 9 14 | 15 | ignoreErrors: 16 | 17 | excludePaths: 18 | - ./*/*/FileToBeExcluded.php 19 | - ./dir/dir/FileToBeExcluded.php 20 | 21 | editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' 22 | 23 | checkMissingIterableValueType: false 24 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | tests 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Facades/LastModified.php: -------------------------------------------------------------------------------- 1 | updatedAt = $updatedAt; 16 | } 17 | 18 | public function get(): ?Carbon 19 | { 20 | return $this->updatedAt; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/LastModifiedServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 17 | $this->publishes([ 18 | __DIR__ . '/../config/last-modified.php' => config_path('last-modified.php'), 19 | ], 'last-modified-config'); 20 | } 21 | } 22 | 23 | /** 24 | * Register the application services. 25 | */ 26 | public function register(): void 27 | { 28 | $this->mergeConfigFrom(__DIR__ . '/../config/last-modified.php', 'last-modified'); 29 | $this->app->singleton('laravel-last-modified', fn () => new LastModified()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Middleware/LastModifiedHandling.php: -------------------------------------------------------------------------------- 1 | getMethod()), ['GET', 'HEAD'])) { 33 | return $response; 34 | } 35 | 36 | if ($response instanceof Response) { 37 | $response->header('Last-Modified', LastModified::get()->toRfc7231String()); 38 | } 39 | 40 | $requestDateTimeString = request()->header('If-Modified-Since'); 41 | if (!is_string($requestDateTimeString)) { 42 | return $response; 43 | } 44 | 45 | if (LastModified::get()->lessThanOrEqualTo(Carbon::createFromTimeString($requestDateTimeString, 'GMT'))) { 46 | abort(304); 47 | } 48 | 49 | return $response; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/LastModifiedHandlingTest.php: -------------------------------------------------------------------------------- 1 | headers = [ 22 | 'If-Modified-Since' => now()->subHour()->toRfc7231String() 23 | ]; 24 | 25 | Route::any('/dummy-post-without-last-modified', function () { 26 | LastModified::set(null); 27 | 28 | return 'nice'; 29 | })->middleware(LastModifiedHandling::class); 30 | 31 | Route::any('/dummy-post-yesterday-update', function () { 32 | LastModified::set(now()->subDay()); 33 | 34 | return 'nice'; 35 | })->middleware(LastModifiedHandling::class); 36 | 37 | Route::any('/dummy-post-today-update', function () { 38 | LastModified::set(now()); 39 | 40 | return 'nice'; 41 | })->middleware(LastModifiedHandling::class); 42 | } 43 | 44 | protected function getPackageProviders($app): array 45 | { 46 | return [ 47 | LastModifiedServiceProvider::class, 48 | ]; 49 | } 50 | 51 | public function testWithoutIfModifiedSinceHeader(): void 52 | { 53 | $this->get('/dummy-post-without-last-modified')->assertOk(); 54 | $this->get('/dummy-post-yesterday-update')->assertOk(); 55 | $this->get('/dummy-post-today-update')->assertOk(); 56 | } 57 | 58 | public function testWithIfModifiedSinceHeader(): void 59 | { 60 | $this->get('/dummy-post-without-last-modified', $this->headers)->assertOk(); 61 | $this->get('/dummy-post-today-update', $this->headers)->assertOk(); 62 | } 63 | 64 | public function testPostMethod(): void 65 | { 66 | $this->post('/dummy-post-yesterday-update', [], $this->headers)->assertOk(); 67 | } 68 | 69 | public function testDisableLastModified(): void 70 | { 71 | config(['last-modified.enable' => false]); 72 | $this->get('/dummy-post-yesterday-update', $this->headers)->assertOk(); 73 | config(['last-modified.enable' => true]); 74 | } 75 | 76 | public function test304(): void 77 | { 78 | $this->get('/dummy-post-yesterday-update', $this->headers)->assertStatus(304); 79 | } 80 | } 81 | --------------------------------------------------------------------------------