Compare commits

...
22 Commits
Author SHA1 Message Date
Joel Male 34626eef5e chore: bump version to 2.1.2 2026-05-29 14:12:49 +10:00
Joel Male 6020b655e2 Merge pull request #12 from wearepixel/fix/phpstan-facade-types
fix: add PHPStan/Larastan support to CartFacade
2026-05-29 14:11:47 +10:00
Joel Male 2c56062f97 fix: add @mixin and @method PHPDoc to CartFacade for PHPStan/Larastan support 2026-05-29 14:09:15 +10:00
Joel Male b2a4864675 chore: ignore docs/superpowers/ 2026-05-27 20:22:32 +10:00
Joel Male aaa3360d1f chore: add test bootstrap, update phpunit config, and add Laravel 13 support to README
- Add tests/bootstrap.php to suppress PHP 8.4 vendor deprecation notices (Mockery implicit-nullable)
- Update phpunit.xml.dist to reference bootstrap, use PHPUnit 11.5 schema, and ignore indirect deprecations
- Note Laravel 13 support in README
2026-05-27 19:50:09 +10:00
Joel Male 05729b7865 chore: bump version to 2.1.1 2026-05-27 16:42:52 +10:00
Joel Male 7e6ee749bf Merge pull request #10 from wearepixel/dependabot/composer/pestphp/pest-4.7.0
chore(deps-dev): bump pestphp/pest from 3.x-dev to 4.7.0
2026-05-27 16:42:24 +10:00
Joel Male 17532f1b05 chore(deps-dev): bump pestphp/pest from 3.x-dev to 4.7.0
Resolves merge conflict with laravel/pint update - regenerated lock file
to include both pint 1.29.1 and pest 4.7.0 with all dependencies.
2026-05-27 16:42:16 +10:00
Joel Male d058ad5521 Merge pull request #9 from wearepixel/dependabot/composer/php-minor-patch-d003f11a51
chore(deps-dev): bump laravel/pint from 1.21.0 to 1.29.1 in the php-minor-patch group
2026-05-27 16:41:05 +10:00
Joel Male 3f5e9374c3 Merge pull request #8 from wearepixel/dependabot/github_actions/actions-c77b365b7e
chore(deps): bump the actions group across 1 directory with 3 updates
2026-05-27 16:41:02 +10:00
Joel Male fcdd356718 fix: update CI runner from deprecated ubuntu-20.04 to ubuntu-latest 2026-05-27 16:40:41 +10:00
dependabot[bot] 3500fa43a9 chore(deps): bump the actions group across 1 directory with 3 updates
Bumps the actions group with 3 updates in the / directory: [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata), [actions/checkout](https://github.com/actions/checkout) and [nick-fields/retry](https://github.com/nick-fields/retry).


Updates `dependabot/fetch-metadata` from 2.2.0 to 3.1.0
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/dbb049abf0d677abbd7f7eee0375145b417fdd34...25dd0e34f4fe68f24cc83900b1fe3fe149efef98)

Updates `actions/checkout` from 4.3.1 to 6.0.2
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/34e114876b0b11c390a56381ad16ebd13914f8d5...de0fac2e4500dabe0009e67214ff5f5447ce83dd)

Updates `nick-fields/retry` from 3.0.2 to 4.0.0
- [Release notes](https://github.com/nick-fields/retry/releases)
- [Commits](https://github.com/nick-fields/retry/compare/ce71cc2ab81d554ebbe88c79ab5975992d79ba08...ad984534de44a9489a53aefd81eb77f87c70dc60)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: dependabot/fetch-metadata
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: nick-fields/retry
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-27 06:26:30 +00:00
Joel Male 28a72581fc chore: pin GitHub Actions to full commit SHAs
chore: pin GitHub Actions to full commit SHAs
2026-05-27 16:24:23 +10:00
dependabot[bot] ddcf38dab0 chore(deps-dev): bump pestphp/pest from 3.x-dev to 4.7.0
Bumps [pestphp/pest](https://github.com/pestphp/pest) from 3.x-dev to 4.7.0.
- [Release notes](https://github.com/pestphp/pest/releases)
- [Changelog](https://github.com/pestphp/pest/blob/4.x/RELEASE.md)
- [Commits](https://github.com/pestphp/pest/commits/v4.7.0)

---
updated-dependencies:
- dependency-name: pestphp/pest
  dependency-version: 4.7.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-27 06:19:38 +00:00
dependabot[bot] e7bf1ba3a3 chore(deps-dev): bump laravel/pint in the php-minor-patch group
Bumps the php-minor-patch group with 1 update: [laravel/pint](https://github.com/laravel/pint).


Updates `laravel/pint` from 1.21.0 to 1.29.1
- [Release notes](https://github.com/laravel/pint/releases)
- [Changelog](https://github.com/laravel/pint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/laravel/pint/compare/v1.21.0...v1.29.1)

---
updated-dependencies:
- dependency-name: laravel/pint
  dependency-version: 1.29.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: php-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-27 06:19:22 +00:00
pixel-workflows[bot] ebf5a41e01 chore: update dependabot configuration 2026-05-27 06:18:28 +00:00
Joel Male e0d566cebd chore: pin GitHub Actions to full commit SHAs
Pins all GitHub Actions uses: references to full commit SHAs
to prevent supply chain attacks via mutable action tags.
Original tag references are kept as inline comments.
2026-05-27 14:46:49 +10:00
Joel Male 863ef52e8d Revise security policy and reporting guidelines
Removed supported versions section and updated reporting instructions.
2026-05-27 14:46:49 +10:00
Joel Male 6638f812c8 chore: bump version to 2.1.0 2026-03-24 14:06:08 +10:00
Joel Male 8f442f51e0 chore: migrate to wearepixel/laravel-cart 2026-03-24 14:04:48 +10:00
Joel Male 6dfd0ce761 chore: bump version to 2.0.0 2026-03-23 16:30:38 +10:00
Joel Male a3161888aa chore: bump to v2.0.0 with PHP 8.3+ support and invalid item cleanup 2026-03-23 16:28:53 +10:00
38 changed files with 1240 additions and 850 deletions
+21 -5
View File
@@ -1,17 +1,33 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
target-branch: "master"
schedule: schedule:
interval: "weekly" interval: "weekly"
day: "monday"
open-pull-requests-limit: 10
groups:
actions:
patterns: ["*"]
commit-message:
prefix: "chore"
include: "scope"
labels: labels:
- "deps" - "dependencies"
- package-ecosystem: "composer" - package-ecosystem: "composer"
directory: "/" directory: "/"
target-branch: "master"
schedule: schedule:
interval: "weekly" interval: "weekly"
day: "tuesday"
open-pull-requests-limit: 10
groups:
php-minor-patch:
update-types:
- "minor"
- "patch"
commit-message:
prefix: "chore"
include: "scope"
labels: labels:
- "deps" - "dependencies"
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
- name: Dependabot metadata - name: Dependabot metadata
id: metadata id: metadata
uses: dependabot/fetch-metadata@v2.2.0 uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
with: with:
github-token: "${{ secrets.GITHUB_TOKEN }}" github-token: "${{ secrets.GITHUB_TOKEN }}"
+6 -7
View File
@@ -9,19 +9,19 @@ on:
jobs: jobs:
tests: tests:
name: Tests name: Tests
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
php: ['8.2', '8.3', '8.4'] php: ["8.3", "8.4", "8.5"]
stability: [prefer-stable] stability: [prefer-stable]
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis, memcached extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis, memcached
@@ -29,12 +29,11 @@ jobs:
coverage: none coverage: none
- name: Install dependencies - name: Install dependencies
uses: nick-fields/retry@v3 uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with: with:
timeout_minutes: 5 timeout_minutes: 5
max_attempts: 5 max_attempts: 5
command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress ${{ matrix.flags }} command: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress ${{ matrix.flags }}
- name: Execute tests - name: Execute tests
run: vendor/bin/pest run: vendor/bin/pest
+2 -1
View File
@@ -3,4 +3,5 @@
.idea .idea
.phpunit.result.cache .phpunit.result.cache
READMETODO.md READMETODO.md
build build
docs/superpowers/
+22 -21
View File
@@ -1,19 +1,20 @@
<a name="top"></a> <a name="top"></a>
[![Laravel Cart](./docs/laravel-cart.png)](https://joelmale.com) [![Laravel Cart](./docs/laravel-cart.png)](https://joelmale.com)
[![Latest Version on Packagist](https://img.shields.io/packagist/v/joelwmale/laravel-cart.svg?style=flat-square)](https://packagist.org/packages/joelwmale/laravel-cart) [![Latest Version on Packagist](https://img.shields.io/packagist/v/wearepixel/laravel-cart.svg?style=flat-square)](https://packagist.org/packages/wearepixel/laravel-cart)
[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/joelwmale/laravel-cart/tests.yml?branch=master&label=Tests)](https://github.com/joelwmale/laravel-cart/actions?query=workflow%3ATests+branch%3Amaster) [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/wearepixel/laravel-cart/tests.yml?branch=master&label=Tests)](https://github.com/wearepixel/laravel-cart/actions?query=workflow%3ATests+branch%3Amaster)
[![Total Downloads](https://img.shields.io/packagist/dt/joelwmale/laravel-cart.svg?style=flat-square)](https://packagist.org/packages/joelwmale/laravel-cart) [![Total Downloads](https://img.shields.io/packagist/dt/wearepixel/laravel-cart.svg?style=flat-square)](https://packagist.org/packages/wearepixel/laravel-cart)
[![GitHub last commit](https://img.shields.io/github/last-commit/joelwmale/laravel-cart)](#) [![GitHub last commit](https://img.shields.io/github/last-commit/wearepixel/laravel-cart)](#)
[![License](https://poser.pugx.org/joelwmale/laravel-cart/license.svg)](https://packagist.org/packages/joelwmale/laravel-cart) [![License](https://poser.pugx.org/wearepixel/laravel-cart/license.svg)](https://packagist.org/packages/wearepixel/laravel-cart)
[![Free](https://img.shields.io/badge/free_for_non_commercial_use-brightgreen)](#-license) [![Free](https://img.shields.io/badge/free_for_non_commercial_use-brightgreen)](#-license)
A Cart Implementation for Laravel. A Cart Implementation for Laravel.
Supported Laravel Versions: 10, 11, and 12. Supported Laravel Versions: 10, 11, 12, and 13.
For Laravel 9.0 and below, please use version [1.0](https://github.com/joelwmale/laravel-cart/releases/tag/1.0.12) For Laravel 9.0 and below, please use version [1.0](https://github.com/wearepixel/laravel-cart/releases/tag/1.0.12)
## Table of Contents ## Table of Contents
- [Getting Started](#-getting-started) - [Getting Started](#-getting-started)
- [Demo](#-deni) - [Demo](#-deni)
- [Documentation](#-documentation) - [Documentation](#-documentation)
@@ -27,11 +28,12 @@ ## Table of Contents
- [License](#-license) - [License](#-license)
## 🚀 Getting Started ## 🚀 Getting Started
### 🔥 Installing ### 🔥 Installing
Install the package through [Composer](http://getcomposer.org/). Install the package through [Composer](http://getcomposer.org/).
`composer require joelwmale/laravel-cart` `composer require wearepixel/laravel-cart`
## 🧑‍🍳 Demo ## 🧑‍🍳 Demo
@@ -71,7 +73,7 @@ ### ⚙️ Configuration
You can publish the configuration file to customize various options. You can publish the configuration file to customize various options.
```php ```php
php artisan vendor:publish --provider="Joelwmale\Cart\CartServiceProvider" --tag="config" php artisan vendor:publish --provider="Wearepixel\Cart\CartServiceProvider" --tag="config"
``` ```
#### Formatting Numbers #### Formatting Numbers
@@ -107,7 +109,6 @@ #### Round Mode
'round_mode' => env('LARAVEL_CART_ROUND_MODE', 'down'), 'round_mode' => env('LARAVEL_CART_ROUND_MODE', 'down'),
``` ```
### Basic Usage ### Basic Usage
The cart has a default sessionKey that holds the cart data and stores it in the session, so you can have multiple carts for multiple users. The cart has a default sessionKey that holds the cart data and stores it in the session, so you can have multiple carts for multiple users.
@@ -168,8 +169,8 @@ #### Adding to the cart: **Cart::add()**
[], // attributes [], // attributes
[ [
[ [
'name' => '10% Off', 'name' => '10% Off',
'type' => 'discount', 'type' => 'discount',
'value' => '-10%' 'value' => '-10%'
] ]
] // conditions ] // conditions
@@ -199,7 +200,7 @@ #### Updating an item on a cart: **Cart::update()**
```php ```php
Cart::update( Cart::update(
456, # product id 456, # product id
[ [
'name' => 'New Item Name', // new item name 'name' => 'New Item Name', // new item name
'price' => 98.67, // new item price as a float or string 'price' => 98.67, // new item price as a float or string
] ]
@@ -215,7 +216,7 @@ #### Updating an item on a cart: **Cart::update()**
// reducing it... // reducing it...
Cart::update( Cart::update(
456, 456,
[ [
'quantity' => -1, // so if from 4 to 3 'quantity' => -1, // so if from 4 to 3
] ]
@@ -328,7 +329,7 @@ ##### Adding a condition to the cart: **Cart::condition()**
```php ```php
// Add a single condition to the cart // Add a single condition to the cart
$condition = new \Joelwmale\Cart\CartCondition([ $condition = new \Wearepixel\Cart\CartCondition([
'name' => 'Tax: 10%', 'name' => 'Tax: 10%',
'type' => 'tax', 'type' => 'tax',
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called. 'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
@@ -341,7 +342,7 @@ ##### Adding a condition to the cart: **Cart::condition()**
Cart::condition($condition); Cart::condition($condition);
// Add multiple conditions // Add multiple conditions
$tax = new \Joelwmale\Cart\CartCondition([ $tax = new \Wearepixel\Cart\CartCondition([
'name' => 'Tax: 10%', 'name' => 'Tax: 10%',
'type' => 'tax', 'type' => 'tax',
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called. 'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
@@ -349,7 +350,7 @@ ##### Adding a condition to the cart: **Cart::condition()**
'order' => 2 'order' => 2
]); ]);
$shipping = new \Joelwmale\Cart\CartCondition([ $shipping = new \Wearepixel\Cart\CartCondition([
'name' => 'Shipping: $15', 'name' => 'Shipping: $15',
'type' => 'shipping', 'type' => 'shipping',
'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called. 'target' => 'subtotal', // this condition will be applied to cart's subtotal when getSubTotal() is called.
@@ -364,7 +365,7 @@ ##### Adding a condition to the cart: **Cart::condition()**
Cart::condition([$tax, $shipping]); Cart::condition([$tax, $shipping]);
// add condition to only apply on totals, not in subtotal // add condition to only apply on totals, not in subtotal
$shipping = new \Joelwmale\Cart\CartCondition([ $shipping = new \Wearepixel\Cart\CartCondition([
'name' => 'Express Shipping $15', 'name' => 'Express Shipping $15',
'type' => 'shipping', 'type' => 'shipping',
'target' => 'total', 'target' => 'total',
@@ -556,7 +557,7 @@ #### Conditions on items
```php ```php
// lets create first our condition instance // lets create first our condition instance
$saleCondition = new \Joelwmale\Cart\CartCondition([ $saleCondition = new \Wearepixel\Cart\CartCondition([
'name' => '50% Off', 'name' => '50% Off',
'type' => 'tax', 'type' => 'tax',
'value' => '-50%', 'value' => '-50%',
@@ -576,7 +577,7 @@ #### Conditions on items
Cart::add($product); Cart::add($product);
// You can of course also do multiple conditions on an item // You can of course also do multiple conditions on an item
$saleCondition = new \Joelwmale\Cart\CartCondition([ $saleCondition = new \Wearepixel\Cart\CartCondition([
'name' => 'SALE 5%', 'name' => 'SALE 5%',
'type' => 'sale', 'type' => 'sale',
'value' => '-5%', 'value' => '-5%',
@@ -841,4 +842,4 @@ ## 🫡 Credits
## 📓 License ## 📓 License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information. The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
+11
View File
@@ -0,0 +1,11 @@
# Security Policy
**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**
## Reporting a Vulnerability
If you discover a security vulnerability, please report it privately using the below channel:
**GitHub Private Vulnerability Reporting** — go to the repository's **Security** tab and click **"Report a vulnerability"**. This creates a private advisory visible only to maintainers and provides a structured workflow for triage, fix coordination, and CVE assignment.
All security vulnerabilities will be promptly addressed.
+17 -17
View File
@@ -1,6 +1,6 @@
{ {
"name": "joelwmale/laravel-cart", "name": "wearepixel/laravel-cart",
"version": "1.2.1", "version": "2.1.2",
"description": "A cart implementation for Laravel", "description": "A cart implementation for Laravel",
"keywords": [ "keywords": [
"laravel", "laravel",
@@ -19,37 +19,37 @@
} }
], ],
"require": { "require": {
"php": ">=8.2", "php": ">=8.3",
"illuminate/support": "^10.0|^11.0|^12.0", "illuminate/support": "^11.0|^12.0|^13.0",
"illuminate/auth": "^10.0|^11.0|^12.0", "illuminate/auth": "^11.0|^12.0|^13.0",
"illuminate/container": "^10.0|^11.0|^12.0", "illuminate/container": "^11.0|^12.0|^13.0",
"illuminate/database": "^10.0|^11.0|^12.0", "illuminate/database": "^11.0|^12.0|^13.0",
"illuminate/validation": "^10.0|^11.0|^12.0" "illuminate/validation": "^11.0|^12.0|^13.0"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^1.6", "mockery/mockery": "^2.0",
"laravel/pint": "^1.21", "laravel/pint": "^1.21",
"pestphp/pest": "^3.0", "pestphp/pest": "^4.7",
"larapack/dd": "dev-master" "larapack/dd": "dev-master"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Joelwmale\\Cart\\": "src/" "Wearepixel\\Cart\\": "src/"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"Tests\\": "tests/" "Tests\\": "tests/"
} }
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"laravel": { "laravel": {
"providers": [ "providers": [
"Joelwmale\\Cart\\CartServiceProvider" "Wearepixel\\Cart\\CartServiceProvider"
], ],
"aliases": { "aliases": {
"Cart": "Joelwmale\\Cart\\Facades\\CartFacade" "Cart": "Wearepixel\\Cart\\Facades\\CartFacade"
} }
} }
}, },
Generated
+1020 -720
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 41 KiB

+3 -7
View File
@@ -1,15 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/bootstrap.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd">
bootstrap="vendor/autoload.php" <source ignoreIndirectDeprecations="true">
colors="true"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd"
>
<source>
<include> <include>
<directory suffix=".php">./src</directory> <directory suffix=".php">./src</directory>
</include> </include>
</source> </source>
<testsuites> <testsuites>
<testsuite name="Laravel Cart Test Suite"> <testsuite name="Laravel Cart Test Suite">
<directory>tests</directory> <directory>tests</directory>
</testsuite> </testsuite>
+33 -11
View File
@@ -1,12 +1,12 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Joelwmale\Cart\Helpers\Helpers; use Wearepixel\Cart\Helpers\Helpers;
use Joelwmale\Cart\Validators\CartItemValidator; use Wearepixel\Cart\Validators\CartItemValidator;
use Joelwmale\Cart\Exceptions\InvalidItemException; use Wearepixel\Cart\Exceptions\InvalidItemException;
use Joelwmale\Cart\Exceptions\UnknownModelException; use Wearepixel\Cart\Exceptions\UnknownModelException;
use Joelwmale\Cart\Exceptions\InvalidConditionException; use Wearepixel\Cart\Exceptions\InvalidConditionException;
class Cart class Cart
{ {
@@ -165,9 +165,31 @@ public function add(
$this->currentItemId = $id; $this->currentItemId = $id;
// clean up any incomplete items
$this->removeInvalidItems();
return $this; return $this;
} }
/**
* Remove any incomplete items
*/
public function removeInvalidItems(): bool
{
$carts = $this->getContent();
foreach ($carts as $index => $cart) {
if (! (isset($cart['id'], $cart['name'], $cart['quantity']))) {
// remove item
$this->remove($index);
}
}
return true;
}
/** /**
* Update a cart item with whatever data is passed in * Update a cart item with whatever data is passed in
*/ */
@@ -232,11 +254,11 @@ public function setConfig($config)
public function addItemCondition($productId, $itemCondition) public function addItemCondition($productId, $itemCondition)
{ {
if ($product = $this->get($productId)) { if ($product = $this->get($productId)) {
$conditionInstance = '\\Joelwmale\\Cart\\CartCondition'; $conditionInstance = '\\Wearepixel\\Cart\\CartCondition';
if ($itemCondition instanceof $conditionInstance) { if ($itemCondition instanceof $conditionInstance) {
// we need to copy first to a temporary variable to hold the conditions // we need to copy first to a temporary variable to hold the conditions
// to avoid hitting this error "Indirect modification of overloaded element of Joelwmale\Cart\ItemCollection has no effect" // to avoid hitting this error "Indirect modification of overloaded element of Wearepixel\Cart\ItemCollection has no effect"
// this is due to laravel Collection instance that implements Array Access // this is due to laravel Collection instance that implements Array Access
// // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect // // see link for more info: http://stackoverflow.com/questions/20053269/indirect-modification-of-overloaded-element-of-splfixedarray-has-no-effect
$itemConditionTempHolder = $product['conditions']; $itemConditionTempHolder = $product['conditions'];
@@ -323,7 +345,7 @@ public function condition(array|CartCondition $condition): self
} }
if (! $condition instanceof CartCondition) { if (! $condition instanceof CartCondition) {
throw new InvalidConditionException('Argument 1 must be an instance of \'Joelwmale\Cart\CartCondition\''); throw new InvalidConditionException('Argument 1 must be an instance of \'Wearepixel\Cart\CartCondition\'');
} }
$conditions = $this->getConditions(); $conditions = $this->getConditions();
@@ -465,7 +487,7 @@ public function removeItemCondition($itemId, $conditionName)
// on the given condition name the user wants to remove, if so, // on the given condition name the user wants to remove, if so,
// lets just make $item['conditions'] an empty array as there's just 1 condition on it anyway // lets just make $item['conditions'] an empty array as there's just 1 condition on it anyway
else { else {
$conditionInstance = 'Joelwmale\\Cart\\CartCondition'; $conditionInstance = 'Wearepixel\\Cart\\CartCondition';
if ($item['conditions'] instanceof $conditionInstance) { if ($item['conditions'] instanceof $conditionInstance) {
if ($tempConditionsHolder->getName() == $conditionName) { if ($tempConditionsHolder->getName() == $conditionName) {
@@ -766,7 +788,7 @@ protected function itemHasConditions($item)
return count($item['conditions']) > 0; return count($item['conditions']) > 0;
} }
$conditionInstance = 'Joelwmale\\Cart\\CartCondition'; $conditionInstance = 'Wearepixel\\Cart\\CartCondition';
if ($item['conditions'] instanceof $conditionInstance) { if ($item['conditions'] instanceof $conditionInstance) {
return true; return true;
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
+4 -4
View File
@@ -1,10 +1,10 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Joelwmale\Cart\Helpers\Helpers; use Wearepixel\Cart\Helpers\Helpers;
use Joelwmale\Cart\Validators\CartConditionValidator; use Wearepixel\Cart\Validators\CartConditionValidator;
use Joelwmale\Cart\Exceptions\InvalidConditionException; use Wearepixel\Cart\Exceptions\InvalidConditionException;
class CartCondition class CartCondition
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
+2 -2
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
class CartSession class CartSession
{ {
@@ -43,7 +43,7 @@ public function isInternalSession($session)
{ {
return in_array(is_object($session) ? get_class($session) : $session, [ return in_array(is_object($session) ? get_class($session) : $session, [
'Illuminate\Session\SessionManager', 'Illuminate\Session\SessionManager',
'Joelwmale\Cart\Tests\Helpers\SessionMock', 'Wearepixel\Cart\Tests\Helpers\SessionMock',
]); ]);
} }
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
namespace Joelwmale\Cart\Exceptions; namespace Wearepixel\Cart\Exceptions;
class InvalidConditionException extends \Exception {} class InvalidConditionException extends \Exception {}
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
namespace Joelwmale\Cart\Exceptions; namespace Wearepixel\Cart\Exceptions;
class InvalidItemException extends \Exception {} class InvalidItemException extends \Exception {}
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
namespace Joelwmale\Cart\Exceptions; namespace Wearepixel\Cart\Exceptions;
class UnknownModelException extends \Exception {} class UnknownModelException extends \Exception {}
+32 -2
View File
@@ -1,12 +1,42 @@
<?php <?php
namespace Joelwmale\Cart\Facades; namespace Wearepixel\Cart\Facades;
use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\Facade;
use Wearepixel\Cart\Cart;
use Wearepixel\Cart\CartCollection;
use Wearepixel\Cart\CartCondition;
use Wearepixel\Cart\CartConditionCollection;
use Wearepixel\Cart\ItemCollection;
/**
* @mixin Cart
*
* @method static ItemCollection|null get(int|string $itemId)
* @method static bool has(int|string $itemId)
* @method static void add(int|string $id, string $name, int|float $price, int $quantity, array $attributes = [], CartCondition|array $conditions = [], string $associatedModel = '')
* @method static bool update(int|string $id, array $data)
* @method static void remove(int|string $id)
* @method static void clear()
* @method static void clearItems()
* @method static Cart condition(array|CartCondition $condition)
* @method static CartConditionCollection|array getConditions(bool $array = false, bool $active = false)
* @method static CartCondition|null getCondition(string $conditionName)
* @method static CartConditionCollection getConditionsByType(string $type)
* @method static void removeConditionsByType(string $type)
* @method static void removeCartCondition(string $conditionName)
* @method static void clearItemConditions(int|string $itemId)
* @method static void clearAllConditions()
* @method static CartCollection getContent()
* @method static bool isEmpty()
* @method static int getTotalQuantity()
* @method static int|float|string getSubTotal(bool $formatted = true)
* @method static int|float|string getSubTotalWithoutConditions(bool $formatted = true)
* @method static int|float getTotal()
*/
class CartFacade extends Facade class CartFacade extends Facade
{ {
protected static function getFacadeAccessor() protected static function getFacadeAccessor(): string
{ {
return 'cart'; return 'cart';
} }
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart\Helpers; namespace Wearepixel\Cart\Helpers;
class Helpers class Helpers
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
+3 -3
View File
@@ -1,9 +1,9 @@
<?php <?php
namespace Joelwmale\Cart; namespace Wearepixel\Cart;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Joelwmale\Cart\Helpers\Helpers; use Wearepixel\Cart\Helpers\Helpers;
class ItemCollection extends Collection class ItemCollection extends Collection
{ {
@@ -72,7 +72,7 @@ public function hasConditions()
if (is_array($this['conditions'])) { if (is_array($this['conditions'])) {
return count($this['conditions']) > 0; return count($this['conditions']) > 0;
} }
$conditionInstance = 'Joelwmale\\Cart\\CartCondition'; $conditionInstance = 'Wearepixel\\Cart\\CartCondition';
if ($this['conditions'] instanceof $conditionInstance) { if ($this['conditions'] instanceof $conditionInstance) {
return true; return true;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
namespace Joelwmale\Cart\Validators; namespace Wearepixel\Cart\Validators;
class CartConditionValidator extends Validator {} class CartConditionValidator extends Validator {}
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
namespace Joelwmale\Cart\Validators; namespace Wearepixel\Cart\Validators;
class CartItemValidator extends Validator {} class CartItemValidator extends Validator {}
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart\Validators; namespace Wearepixel\Cart\Validators;
use Illuminate\Validation\Factory; use Illuminate\Validation\Factory;
use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\Filesystem;
+1 -1
View File
@@ -8,7 +8,7 @@
'storage' => [ 'storage' => [
'session', 'session',
'database' => [ 'database' => [
'model' => \Joelwmale\Cart\Tests\Helpers\MockCartModel::class, 'model' => \Wearepixel\Cart\Tests\Helpers\MockCartModel::class,
'id' => 'session_id', 'id' => 'session_id',
'items' => 'items', 'items' => 'items',
'conditions' => 'conditions', 'conditions' => 'conditions',
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart\Tests\Helpers; namespace Wearepixel\Cart\Tests\Helpers;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart\Tests\Helpers; namespace Wearepixel\Cart\Tests\Helpers;
use Illuminate\Contracts\Database\ModelIdentifier; use Illuminate\Contracts\Database\ModelIdentifier;
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
namespace Joelwmale\Cart\Tests\Helpers; namespace Wearepixel\Cart\Tests\Helpers;
class SessionMock class SessionMock
{ {
+4 -4
View File
@@ -1,9 +1,9 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\CartCondition; use Wearepixel\Cart\CartCondition;
use Joelwmale\Cart\CartConditionCollection; use Wearepixel\Cart\CartConditionCollection;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
+10 -10
View File
@@ -1,8 +1,8 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\Tests\Helpers\MockProduct; use Wearepixel\Cart\Tests\Helpers\MockProduct;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
@@ -149,7 +149,7 @@
$item = $this->cart->get(1); $item = $this->cart->get(1);
expect($item->attributes)->toBeInstanceOf('Joelwmale\\Cart\\ItemAttributeCollection'); expect($item->attributes)->toBeInstanceOf('Wearepixel\\Cart\\ItemAttributeCollection');
// now lets update the item with its new attributes // now lets update the item with its new attributes
// when we get that item from cart, it should still be an instance of ItemAttributeCollection // when we get that item from cart, it should still be an instance of ItemAttributeCollection
@@ -162,7 +162,7 @@
$this->cart->update(1, $updatedItem); $this->cart->update(1, $updatedItem);
expect($item->attributes)->toBeInstanceOf('Joelwmale\\Cart\\ItemAttributeCollection'); expect($item->attributes)->toBeInstanceOf('Wearepixel\\Cart\\ItemAttributeCollection');
}); });
test('item orders are preserved by the order they are added', function () { test('item orders are preserved by the order they are added', function () {
@@ -298,19 +298,19 @@
}); });
test('should throw an exception when no quantity is provided', function () { test('should throw an exception when no quantity is provided', function () {
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException'); $this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
$this->expectExceptionMessage('The quantity must be at least 0.1.'); $this->expectExceptionMessage('The quantity must be at least 0.1.');
$this->cart->add(455, 'Sample Item', 100.99, 0, []); $this->cart->add(455, 'Sample Item', 100.99, 0, []);
}); });
test('should throw an exception when no id is provided', function () { test('should throw an exception when no id is provided', function () {
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException'); $this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
$this->expectExceptionMessage('The id field is required.'); $this->expectExceptionMessage('The id field is required.');
$this->cart->add('', 'Sample Item', 100.99, 2, []); $this->cart->add('', 'Sample Item', 100.99, 2, []);
}); });
test('should throw an exception when no name is provided', function () { test('should throw an exception when no name is provided', function () {
$this->expectException('Joelwmale\Cart\Exceptions\InvalidItemException'); $this->expectException('Wearepixel\Cart\Exceptions\InvalidItemException');
$this->expectExceptionMessage('The name field is required.'); $this->expectExceptionMessage('The name field is required.');
$this->cart->add(523, '', 100.99, 2, []); $this->cart->add(523, '', 100.99, 2, []);
}); });
@@ -646,7 +646,7 @@
expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it'); expect($this->cart->getContent()->count())->toEqual(1, 'Cart should have 1 item on it');
expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456'); expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456');
expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"'); expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"');
expect($addedItem->model)->toBeInstanceOf('Joelwmale\Cart\Tests\Helpers\MockProduct'); expect($addedItem->model)->toBeInstanceOf('Wearepixel\Cart\Tests\Helpers\MockProduct');
}); });
test('cart can add items with multidimensional array with associated model', function () { test('cart can add items with multidimensional array with associated model', function () {
@@ -681,7 +681,7 @@
$content = $this->cart->getContent(); $content = $this->cart->getContent();
foreach ($content as $item) { foreach ($content as $item) {
expect($item->model)->toBeInstanceOf('Joelwmale\Cart\Tests\Helpers\MockProduct'); expect($item->model)->toBeInstanceOf('Wearepixel\Cart\Tests\Helpers\MockProduct');
} }
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty'); expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
+7 -7
View File
@@ -1,7 +1,7 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () {}); beforeEach(function () {});
@@ -25,7 +25,7 @@
}); });
test('event cart adding', function () { test('event cart adding', function () {
$events = Mockery::mock('Illuminate\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Adding', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Adding', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Added', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Added', Mockery::type('array'), true);
@@ -44,7 +44,7 @@
}); });
test('event cart adding multiple times', function () { test('event cart adding multiple times', function () {
$events = Mockery::mock('Illuminate\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Adding', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Adding', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Added', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(2)->with('LaravelCart.Added', Mockery::type('array'), true);
@@ -64,7 +64,7 @@
}); });
test('event cart adding multiple times scenario two', function () { test('event cart adding multiple times scenario two', function () {
$events = Mockery::mock('Illuminate\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
@@ -107,7 +107,7 @@
}); });
test('event cart remove item', function () { test('event cart remove item', function () {
$events = Mockery::mock('Illuminate\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
@@ -154,7 +154,7 @@
}); });
test('event cart clear', function () { test('event cart clear', function () {
$events = Mockery::mock('Illuminate\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true); $events->shouldReceive('dispatch')->once()->with('LaravelCart.Created', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Adding', Mockery::type('array'), true);
$events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true); $events->shouldReceive('dispatch')->times(3)->with('LaravelCart.Added', Mockery::type('array'), true);
+2 -2
View File
@@ -1,7 +1,7 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
+3 -3
View File
@@ -1,8 +1,8 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\CartCondition; use Wearepixel\Cart\CartCondition;
use Joelwmale\Cart\Tests\Helpers\MockCartModel; use Wearepixel\Cart\Tests\Helpers\MockCartModel;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
+6 -6
View File
@@ -1,9 +1,9 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\CartCondition; use Wearepixel\Cart\CartCondition;
use Joelwmale\Cart\Tests\Helpers\MockProduct; use Wearepixel\Cart\Tests\Helpers\MockProduct;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
@@ -47,7 +47,7 @@
}); });
test('item get conditions with conditions', function () { test('item get conditions with conditions', function () {
$itemCondition1 = new \Joelwmale\Cart\CartCondition([ $itemCondition1 = new \Wearepixel\Cart\CartCondition([
'name' => 'SALE 5%', 'name' => 'SALE 5%',
'type' => 'sale', 'type' => 'sale',
'target' => 'item', 'target' => 'item',
@@ -77,7 +77,7 @@
}); });
test('it will throw an exception when a non existing model is being associated', function () { test('it will throw an exception when a non existing model is being associated', function () {
$this->expectException(\Joelwmale\Cart\Exceptions\UnknownModelException::class); $this->expectException(\Wearepixel\Cart\Exceptions\UnknownModelException::class);
$this->expectExceptionMessage('The supplied model SomeModel does not exist.'); $this->expectExceptionMessage('The supplied model SomeModel does not exist.');
$this->cart->add(1, 'Test item', 1, 10.00)->associate('SomeModel'); $this->cart->add(1, 'Test item', 1, 10.00)->associate('SomeModel');
+2 -2
View File
@@ -1,7 +1,7 @@
<?php <?php
use Joelwmale\Cart\Cart; use Wearepixel\Cart\Cart;
use Joelwmale\Cart\Tests\Helpers\SessionMock; use Wearepixel\Cart\Tests\Helpers\SessionMock;
beforeEach(function () { beforeEach(function () {
$events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher'); $events = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
+14
View File
@@ -0,0 +1,14 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
// Suppress PHP 8.4 deprecation notices that originate from vendor code.
// These are typically from third-party packages (e.g. Mockery) that have not
// yet updated implicit-nullable parameter signatures and are not actionable here.
set_error_handler(static function (int $errno, string $errstr, string $errfile): bool {
if ($errno === E_DEPRECATED && str_contains($errfile, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR)) {
return true;
}
return false;
}, E_DEPRECATED);