├── .codacy.yml
├── .editorconfig
├── .github
└── workflows
│ ├── phpstan.yml
│ └── tests.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── SECURITY.md
├── composer.json
├── config
└── status.php
├── database
└── migrations
│ └── create_statuses_table.php.stub
├── phpstan.neon
├── phpunit.coverage.dist.xml
├── phpunit.dist.xml
├── src
├── Contracts
│ └── Statusable.php
├── EventServiceProvider.php
├── Events
│ └── StatusCreating.php
├── Listeners
│ └── AttachDefaultStatus.php
├── Nova
│ └── Filters
│ │ └── StatusFilter.php
├── Scopes
│ └── DefaultStatusScope.php
├── ServiceProvider.php
├── Status.php
├── StatusBuilder.php
└── Traits
│ └── HasStatuses.php
└── tests
├── Fixtures
├── AnotherStatuses.php
├── Post.php
└── PostStatuses.php
├── StatusTest.php
├── TestCase.php
└── database
└── 0000_00_00_000000_create_posts_test_table.php
/.codacy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | phpcs:
4 | php_version: 7.4-
5 |
6 | exclude_paths:
7 | - "**/tests/**"
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 4
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = false
12 | insert_final_newline = true
13 |
14 | [*.{yml,xml}]
15 | indent_size = 2
16 |
--------------------------------------------------------------------------------
/.github/workflows/phpstan.yml:
--------------------------------------------------------------------------------
1 | name: phpstan
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | analyze:
7 | runs-on: ubuntu-latest
8 |
9 | name: PHPStan
10 |
11 | steps:
12 | - uses: actions/checkout@v2
13 |
14 | - name: Setup PHP
15 | uses: shivammathur/setup-php@v2
16 | with:
17 | php-version: 8.1
18 |
19 | - name: Cache dependencies
20 | uses: actions/cache@v2
21 | with:
22 | path: ${{ steps.composer-cache.outputs.dir }}
23 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
24 | restore-keys: ${{ runner.os }}-composer-prefer-stable-
25 |
26 | - name: Install dependencies
27 | run: |
28 | composer update --prefer-stable --prefer-dist --no-interaction --no-suggest
29 |
30 | - name: Run analysis
31 | run: ./vendor/bin/phpstan analyse
32 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | test:
7 | runs-on: ${{ matrix.os }}
8 |
9 | strategy:
10 | fail-fast: true
11 | matrix:
12 | os: [ ubuntu-latest ]
13 | php: [ 7.4, 8.0, 8.1 ]
14 | laravel: [ 6.*, 8.*, 9.* ]
15 | dependency-version: [ prefer-stable ]
16 | exclude:
17 | # PHP 8.1 is not compatible with Laravel 6!
18 | - laravel: 6.*
19 | php: 8.1
20 | # PHP 7 is not compatible with Laravel 9 and future releases!
21 | - laravel: 9.*
22 | php: 7.4
23 | include:
24 | - laravel: 6.*
25 | testbench: 4.*
26 |
27 | - laravel: 8.*
28 | testbench: 6.*
29 |
30 | - laravel: 9.*
31 | testbench: 7.*
32 |
33 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }}
34 |
35 | steps:
36 | - name: Checkout code
37 | uses: actions/checkout@v1
38 |
39 | - name: Setup PHP
40 | uses: shivammathur/setup-php@v2
41 | with:
42 | php-version: ${{ matrix.php }}
43 | extensions: dom, curl, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, intl, exif
44 | coverage: pcov
45 |
46 | - name: Get composer cache directory
47 | id: composer-cache
48 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
49 |
50 | - name: Cache dependencies
51 | uses: actions/cache@v2
52 | with:
53 | path: ${{ steps.composer-cache.outputs.dir }}
54 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
55 | restore-keys: ${{ runner.os }}-composer-${{ matrix.dependency-version }}-
56 |
57 | - name: Install dependencies
58 | env:
59 | NOVA_USERNAME: ${{ secrets.NOVA_USERNAME }}
60 | NOVA_PASSWORD: ${{ secrets.NOVA_PASSWORD }}
61 | run: |
62 | composer config http-basic.nova.laravel.com $NOVA_USERNAME $NOVA_PASSWORD
63 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
64 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
65 |
66 | - name: Execute tests
67 | run: |
68 | cp phpunit.coverage.dist.xml phpunit.xml || true
69 | vendor/bin/phpunit
70 |
71 | - name: Deploy coverage to codacy
72 | uses: codacy/codacy-coverage-reporter-action@v1
73 | with:
74 | # project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
75 | api-token: ${{ secrets.CODACY_API_TOKEN }}
76 | coverage-reports: clover.xml
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | composer.lock
3 | .phpunit.result.cache
4 | /xml-coverage/
5 | clover.xml
6 | phpunit.xml
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | ## [2.5.2] - 2022-07-15
11 |
12 | ### Fixed
13 |
14 | - Missing autoload-dev, tests were autoloaded with the released version (ouch!)
15 |
16 | ## [2.5.1] - 2022-06-20
17 |
18 | ### Fixed
19 |
20 | - Fix Laravel Nova status filter
21 |
22 | ## [2.5.0] - 2022-06-06
23 |
24 | ### Added
25 |
26 | - `statuses` query scope that accepts multiple statuses names (labels)
27 |
28 | ## [2.4.1] - 2022-03-03
29 |
30 | ### Fixed
31 |
32 | - `creating` event was preventing propagation
33 |
34 | ## [2.4.0] - 2022-02-11
35 |
36 | ### Added
37 |
38 | - Support for Laravel 9
39 |
40 | ### Removed
41 |
42 | - Support for Laravel 7
43 |
44 | ## [2.3.3] - 2021-11-24
45 |
46 | ### Fixed
47 |
48 | - AttachDefaultStatus event population when creating
49 |
50 | ## [2.3.2] - 2021-08-06
51 |
52 | ### Fixed
53 |
54 | - Fix bool return when `setStatus` and `status` methods
55 |
56 | ## [2.3.1] - 2021-07-28
57 |
58 | ### Fixed
59 |
60 | - Camel cased on status checks & toEnums internal functions
61 |
62 | ## [2.3.0] - 2021-07-13
63 |
64 | ### Added
65 |
66 | - More test coverage
67 |
68 | ### Changed
69 |
70 | - More methods now accepting enum classes as inputs: `setStatus` & `setStatusWhen`
71 |
72 | ### Removed
73 |
74 | - Internal method `checkStatus`
75 |
76 | ## [2.2.0] - 2021-07-12
77 |
78 | ### Changed
79 |
80 | - Fixes around conditional assignation `setStatus(['previous' => 'new'])`
81 |
82 | ### Added
83 |
84 | - `Status::toEnum` utility method for transform string value to enum object
85 | - `Model::setStatusWhen` method which works similarly the same as `setStatus`
86 | - More tests around all the exposed and internal methods
87 |
88 | ## [2.1.1] - 2021-07-09
89 |
90 | ### Changed
91 |
92 | - `Model::status()` query scope now accepts enum instances
93 |
94 | ## [2.1.0] - 2021-07-09
95 |
96 | ### Changed
97 |
98 | - `Model::hasStatus()` now accepts enum instances
99 | - Required package `spatie/enum` upgraded to v3
100 | - A lot of simplification all over the place
101 | - Deprecated static method `Status::getDefault()` use instead `Status::defaultFrom($model)` query scope
102 |
103 | ### Added
104 |
105 | - `Status::defaultFrom($model)` local query scope
106 | - `Statusable::statusesClass` static method to get Statuses enum (can be also replaced to your own path)
107 | - Some package tests covering most of its code
108 |
109 | ### Removed
110 |
111 | - `Statusable::statuses` static propery has been removed in favor of `Statusable::statusesClass` to be user configurable
112 |
113 | ## [2.0.3] - 2021-02-23
114 |
115 | ### Fixed
116 |
117 | - Remove lazy eager load of relation on trait (fixes some issues displaying the status relationship on APIs when not requested)
118 |
119 | ## [2.0.2] - 2021-01-20
120 |
121 | ### Fixed
122 |
123 | - Wrong StatusFilter query in Nova
124 |
125 | ## [2.0.1] - 2021-01-20
126 |
127 | ### Added
128 |
129 | - Support for PHP 8
130 | - Default model status query scope class
131 | - Laravel Nova status filter class
132 |
133 | ## [2.0.0] - 2020-11-30
134 |
135 | ### Added
136 |
137 | - Support for Laravel 8
138 |
139 | ### Removed
140 |
141 | - Support for Laravel 5
142 |
143 | ## [1.3.4] - 2020-07-06
144 |
145 | ### Fixed
146 |
147 | - HasStatus method returning wrong thing ([also documented](https://github.com/skore/laravel-status#hasStatus))
148 |
149 | ## [1.3.3] - 2020-07-02
150 |
151 | ### Fixed
152 |
153 | - HasStatus method was returning first string char
154 |
155 | ## [1.3.2] - 2020-04-06
156 |
157 | ### Fixed
158 |
159 | - Rename folder / fix namespace (PSR-4)
160 |
161 | ## [1.3.1] - 2020-03-13
162 |
163 | ### Added
164 |
165 | - Missed config option to the file
166 |
167 | ### Changed
168 |
169 | - Default to true enable_events config option
170 |
171 | ## [1.3.0] - 2020-03-13
172 |
173 | ### Added
174 |
175 | - Config option for enable or disable all the package events
176 |
177 | ### Fixed
178 |
179 | - Change trait event from Model's `dispatchesEvents` to passing callbacks methods
180 | - Saving from a replaced Model's built-in method to another event (`saving`)
181 |
182 | ## [1.2.4] - 2020-03-10
183 |
184 | ### Fixed
185 |
186 | - More fixes around status setter
187 |
188 | ## [1.2.3] - 2020-03-09
189 |
190 | ### Fixed
191 |
192 | - Fixed some issues checking statuses on `setStatus(['previous' => 'new'])`
193 |
194 | ### Changed
195 |
196 | - Minor changes to code style
197 |
198 | ## [1.2.2] - 2020-03-06
199 |
200 | ### Fixed
201 |
202 | - Improved case sensitivity in get/set statuses
203 | - Events names with spaces
204 |
205 | ## [1.2.1] - 2020-03-06
206 |
207 | ### Fixed
208 |
209 | - `HasStatuses::save()` return bool
210 |
211 | ## [1.2.0] - 2020-03-05
212 |
213 | ### Added
214 |
215 | - Compatibility with Laravel 7
216 | - Custom model events on status `saving` and `saved` (e.g. `savingActive` & `savedActive` when save a *non active* model to active)
217 | - EventsServiceProvider (**no need to manually add events to your app's events**)
218 |
219 | ### Changed
220 |
221 | - **Possible breakchange!** Renamed package ServiceProvider (from _StatusServiceProvider_ to _ServiceProvider_)
222 |
223 | ## [1.1.5] - 2020-03-05
224 |
225 | ### Changed
226 |
227 | - Minor changes and optimisations
228 | - Change default config path for models (following Laravel's default one: `App\Model`)
229 |
230 | ## [1.1.4] - 2020-01-12
231 |
232 | ### Fixed
233 |
234 | - Get model class in `Status::getFromEnum()` method (now using `Model::getMorphClass()`)
235 |
236 | ## [1.1.3] - 2020-01-11
237 |
238 | ### Fixed
239 |
240 | - More trait fixes around `getMorphClass()` and the new addons
241 |
242 | ## [1.1.2] - 2020-01-11
243 |
244 | ### Added
245 |
246 | - Custom getter in `HasStatuses` trait for Status custom model
247 |
248 | ### Fixed
249 |
250 | - Get properly the model's morph class by using `getMorphClass()`
251 |
252 | ## [1.1.1] - 2019-12-10
253 |
254 | ### Fixed
255 |
256 | - checkStatus array_walk to array_map
257 | - case sensitive in setStatusAttribute
258 |
259 | ## [1.1.0] - 2019-12-10
260 |
261 | ### Added
262 |
263 | - Use custom Status model (customisable in the config file)
264 |
265 | ### Fixed
266 |
267 | - hasStatus didn't load relation properly
268 |
269 | ### Changed
270 |
271 | - Changes to the config file
272 |
273 | ## [1.0.2] - 2019-12-07
274 |
275 | ### Fixed
276 |
277 | - Variable types and names in docblocks
278 | - Case sensitive in status attribute mutator
279 |
280 | ## [1.0.1] - 2019-12-07
281 |
282 | ### Fixed
283 |
284 | - Missed namespace on Statusable contract
285 |
286 | ## [1.0.0] - 2019-12-07
287 |
288 | ### Added
289 |
290 | - Package published on Packagist (composer)
291 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Skore
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 | # Laravel status
2 |
3 | > ⚠️ **This package is gonna be deprecated in favour of this one: https://github.com/open-southeners/laravel-model-status**
4 |
5 | Laravel code-typed statuses for Eloquent models.
6 |
7 | ## Status
8 |
9 | [](https://packagist.org/packages/skore-labs/laravel-status) [](https://github.com/skore/laravel-status/actions/workflows/tests.yml) [](https://github.styleci.io/repos/226506454) [](https://www.codacy.com/gh/skore/laravel-status/dashboard?utm_source=github.com&utm_medium=referral&utm_content=skore/laravel-status&utm_campaign=Badge_Grade) [](https://www.codacy.com/gh/skore/laravel-status/dashboard?utm_source=github.com&utm_medium=referral&utm_content=skore/laravel-status&utm_campaign=Badge_Coverage) [](https://github.com/skore/laravel-status) [](https://github.com/skore/laravel-status)
10 |
11 | ## Getting started
12 |
13 | You can install the package via composer:
14 |
15 | ```
16 | composer require skore-labs/laravel-status
17 | ```
18 |
19 | Then you will need to publish the package config and migrations, so then you can modify and/or migrate the new statuses table:
20 |
21 | ```
22 | php artisan vendor:publish --provider="SkoreLabs\LaravelStatus\ServiceProvider"
23 | ```
24 |
25 | ### Setup models
26 |
27 | Add statuses to your model by adding `SkoreLabs\LaravelStatus\Traits\HasStatuses` and the interface `SkoreLabs\LaravelStatus\Contracts\Statusable` so that it can pass some predefined events (see above), here's an example:
28 |
29 | ```php
30 | hasStatus('published');
82 |
83 | // Post has status Published or Was Published
84 | $post->hasStatus(['published', 'was published']);
85 | ```
86 |
87 | ### setStatus
88 |
89 | Set status or mutate status **only if the previous status match the key.**
90 |
91 | ```php
92 | // Set post status to Was Published
93 | $post->setStatus('was published');
94 |
95 | // Change if post has status Published to Was Published.
96 | $post->setStatus(['published' => 'was published']);
97 | ```
98 |
99 | You can also use the attribute to set a status:
100 |
101 | ```php
102 | $post->status = 'was published';
103 |
104 | // Better use status method for this
105 | if ($post->hasStatus('published')) {
106 | $post->status = 'was published';
107 | }
108 |
109 | // When save it check and attach the status
110 | $post->save();
111 | ```
112 |
113 | ### setStatusWhen
114 |
115 | You can also do the same with `setStatusWhen` method like the example above with `setStatus`.
116 |
117 | ```php
118 | // Change if post has status Published to Was Published.
119 | $post->setStatusWhen('published', 'was published');
120 | ```
121 |
122 | ### status
123 |
124 | If a parameter is provided, it acts as an alias of [hasStatus](#hasStatus).
125 |
126 | If an associative array is provided, it acts as an alias of [setStatus](#setStatus).
127 |
128 | Otherwise, it will just retrieve the relationship as `$post->status` or `$post->status()->first()`
129 |
130 | Also you can filter by scope:
131 |
132 | ```php
133 | Post::status('published');
134 | Post::where('user_id', Auth::id())->status('published');
135 | ```
136 |
137 | ### statuses
138 |
139 | Get all the possible model statuses.
140 |
141 | ```php
142 | Post::statuses();
143 |
144 | // You can use Status model as well
145 | Status::getFrom(Post::class);
146 | // Also specify value to return like '->value('id')'
147 | Status::getFrom(Post::class, 'id');
148 | // Or return the object with columns like '->first(['id', 'name'])'
149 | Status::getFrom(Post::class, ['id', 'name']);
150 | ```
151 |
152 | ### getDefaultStatus
153 |
154 | Get the model's default status.
155 |
156 | ```php
157 | // Default status for post is Published, so it returns Published
158 | Post::getDefaultStatus();
159 |
160 | // You can use Status model query scope as well
161 | Status::query()->defaultFrom(Post::class)->first();
162 | ```
163 |
164 | ## Support
165 |
166 | This and all of our Laravel packages follows as much as possibly can the LTS support of Laravel.
167 |
168 | Read more: https://laravel.com/docs/master/releases#support-policy
169 |
170 | ## Credits
171 |
172 | - Ruben Robles ([@d8vjork](https://github.com/d8vjork))
173 | - Skore ([https://www.getskore.com/](https://www.getskore.com/))
174 | - Spatie for the Enum package ([https://spatie.be/](https://spatie.be/))
175 | - [And all the contributors](https://github.com/skore-labs/laravel-status/graphs/contributors)
176 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | We're also following the [Laravel's default support policy](https://laravel.com/docs/master/releases#support-policy) on our semantic versioning.
6 |
7 | | Version | Supported |
8 | | ------- | ------------------ |
9 | | 2.x | :white_check_mark: |
10 | | < 2.0 | :x: |
11 |
12 | ## Reporting a Vulnerability
13 |
14 | Send us an email at developers@getskore.com
15 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "skore-labs/laravel-status",
3 | "description": "Laravel code-typed statuses for models",
4 | "license": "MIT",
5 | "keywords": [
6 | "skore-labs",
7 | "laravel",
8 | "statuses",
9 | "eloquent",
10 | "typed"
11 | ],
12 | "authors": [
13 | {
14 | "name": "Ruben Robles",
15 | "email": "d8vjork@outlook.com"
16 | }
17 | ],
18 | "require": {
19 | "php": "^7.2|^8.0|^8.1",
20 | "spatie/enum": "^3.9",
21 | "illuminate/database": "^6.0|^8.0|^9.0",
22 | "illuminate/support": "^6.0|^8.0|^9.0"
23 | },
24 | "require-dev": {
25 | "ext-json": "*",
26 | "laravel/nova": "^2.0|^3.0",
27 | "nunomaduro/larastan": "^1.0|^2.0",
28 | "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0",
29 | "phpstan/phpstan": "^1.4",
30 | "phpunit/phpunit": "^7.0|^9.0"
31 | },
32 | "suggest": {
33 | "laravel/nova": "Required if using status nova filter"
34 | },
35 | "autoload": {
36 | "psr-4": {
37 | "SkoreLabs\\LaravelStatus\\": "src"
38 | }
39 | },
40 | "autoload-dev": {
41 | "psr-4": {
42 | "SkoreLabs\\LaravelStatus\\Tests\\": "tests"
43 | }
44 | },
45 | "config": {
46 | "sort-packages": true
47 | },
48 | "extra": {
49 | "laravel": {
50 | "providers": [
51 | "SkoreLabs\\LaravelStatus\\ServiceProvider"
52 | ]
53 | }
54 | },
55 | "repositories": [
56 | {
57 | "type": "composer",
58 | "url": "https://nova.laravel.com"
59 | }
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/config/status.php:
--------------------------------------------------------------------------------
1 | SkoreLabs\LaravelStatus\Status::class,
6 |
7 | 'enums_path' => 'App\\Enums\\',
8 |
9 | 'models_path' => 'App\\',
10 |
11 | 'enable_events' => true,
12 |
13 | ];
14 |
--------------------------------------------------------------------------------
/database/migrations/create_statuses_table.php.stub:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
13 | $table->string('name');
14 | $table->string('model_type');
15 | $table->boolean('is_default')->default(false);
16 |
17 | $table->unique(['name', 'model_type']);
18 | });
19 | }
20 |
21 | public function down()
22 | {
23 | Schema::dropIfExists('statuses');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | includes:
2 | - ./vendor/nunomaduro/larastan/extension.neon
3 |
4 | parameters:
5 |
6 | paths:
7 | - src
8 |
9 | level: 6
10 |
11 | # ignoreErrors:
12 | # - '#PHPDoc tag @var#'
13 |
14 | checkMissingIterableValueType: false
15 |
--------------------------------------------------------------------------------
/phpunit.coverage.dist.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 | ./src
18 |
19 |
20 | src/EventServiceProvider.php
21 | src/Contracts/Statusable.php
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | tests
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/phpunit.dist.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 | src/
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | tests
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Contracts/Statusable.php:
--------------------------------------------------------------------------------
1 | |string|bool
22 | */
23 | public function status($value = false);
24 |
25 | /**
26 | * Get statuses available for this model as attribute.
27 | *
28 | * @return array
29 | */
30 | public function getStatusesAttribute();
31 |
32 | /**
33 | * Get statuses available for this model.
34 | *
35 | * @return array
36 | */
37 | public static function getStatuses();
38 |
39 | /**
40 | * Set status by label(s) to key and perform a save.
41 | *
42 | * @param array|string|\Spatie\Enum\Enum $name
43 | *
44 | * @return bool
45 | */
46 | public function setStatus($name);
47 |
48 | /**
49 | * Set status when current status is.
50 | *
51 | * @param mixed $current
52 | * @param mixed $new
53 | *
54 | * @return bool
55 | */
56 | public function setStatusWhen($current, $new);
57 |
58 | /**
59 | * Set status relation as attribute.
60 | *
61 | * @param string|\Spatie\Enum\Enum $value
62 | *
63 | * @return void
64 | */
65 | public function setStatusAttribute($value = null);
66 |
67 | /**
68 | * Check current status is equals to.
69 | *
70 | * @param string|array|\Spatie\Enum\Enum $value
71 | *
72 | * @return bool
73 | */
74 | public function hasStatus($value);
75 |
76 | /**
77 | * Get model status or default instead.
78 | *
79 | * @param string $column
80 | *
81 | * @return string|null
82 | */
83 | public function getStatus($column = 'name');
84 |
85 | /**
86 | * Get default status for this model.
87 | *
88 | * @param string|array $column
89 | *
90 | * @return \Illuminate\Database\Eloquent\Model|object|\Illuminate\Database\Eloquent\Builder|null|mixed
91 | */
92 | public static function getDefaultStatus($column = 'name');
93 |
94 | /**
95 | * List all resources of a specified status.
96 | *
97 | * @param \Illuminate\Database\Eloquent\Builder $query
98 | * @param string|\Spatie\Enum\Enum $name
99 | *
100 | * @return \Illuminate\Database\Eloquent\Builder
101 | */
102 | public function scopeStatus(Builder $query, $name);
103 | }
104 |
--------------------------------------------------------------------------------
/src/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
18 | AttachDefaultStatus::class,
19 | ],
20 | ];
21 | }
22 |
--------------------------------------------------------------------------------
/src/Events/StatusCreating.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | public $model;
18 |
19 | /**
20 | * Create a new event instance.
21 | *
22 | * @param \SkoreLabs\LaravelStatus\Contracts\Statusable<\Illuminate\Database\Eloquent\Model> $statusable
23 | *
24 | * @return void
25 | */
26 | public function __construct(Statusable $statusable)
27 | {
28 | $this->model = $statusable;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Listeners/AttachDefaultStatus.php:
--------------------------------------------------------------------------------
1 | model->status_id || !$event->model->status) {
19 | $event->model->status()->associate(
20 | $event->model->getDefaultStatus('id')
21 | );
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Nova/Filters/StatusFilter.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | protected $statusesQuery;
18 |
19 | /**
20 | * @var array|bool
21 | */
22 | protected $defaultOption = false;
23 |
24 | /**
25 | * Create a new filter instance.
26 | *
27 | * @param string $type
28 | *
29 | * @return void
30 | */
31 | public function __construct($type)
32 | {
33 | $this->statusesQuery = Status::where([
34 | 'model_type' => $type,
35 | ]);
36 | }
37 |
38 | /**
39 | * Apply the filter to the given query.
40 | *
41 | * @param \Illuminate\Http\Request $request
42 | * @param \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model> $query
43 | * @param mixed $value
44 | *
45 | * @return \Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>
46 | */
47 | public function apply(Request $request, $query, $value)
48 | {
49 | if (!array_filter($value)) {
50 | return $query;
51 | }
52 |
53 | $i = 0;
54 |
55 | foreach ($value as $status => $enabled) {
56 | if ($enabled) {
57 | $query->where($query->getModel()->getTable().'.status_id', '=', $status, $i === 0 ? 'and' : 'or');
58 | $i++;
59 | }
60 | }
61 |
62 | return $query->withoutGlobalScope(DefaultStatusScope::class);
63 | }
64 |
65 | /**
66 | * Get the filter's available options.
67 | *
68 | * @param \Illuminate\Http\Request $request
69 | *
70 | * @return array
71 | */
72 | public function options(Request $request)
73 | {
74 | return (clone $this->statusesQuery)
75 | ->pluck('id', 'name')
76 | ->all();
77 | }
78 |
79 | /**
80 | * Set the default options for the filter.
81 | *
82 | * @return array|bool
83 | */
84 | public function default()
85 | {
86 | if (!$this->defaultOption) {
87 | return parent::default();
88 | }
89 |
90 | return $this->defaultOption;
91 | }
92 |
93 | /**
94 | * Set option as default initial filter.
95 | *
96 | * @param string $value
97 | *
98 | * @return $this
99 | */
100 | public function setDefault($value)
101 | {
102 | $query = (clone $this->statusesQuery)->where('name', $value);
103 |
104 | if ($query->exists()) {
105 | $this->defaultOption = [$query->value('id') => true];
106 | }
107 |
108 | return $this;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Scopes/DefaultStatusScope.php:
--------------------------------------------------------------------------------
1 | $builder
18 | * @param \Illuminate\Database\Eloquent\Model $model
19 | *
20 | * @return void
21 | */
22 | public function apply(Builder $builder, Model $model)
23 | {
24 | /** @var \SkoreLabs\LaravelStatus\Contracts\Statusable $model */
25 | $builder->where('status_id', $model->getDefaultStatus('id'));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
17 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations/');
18 | }
19 |
20 | if (!class_exists('CreateStatusesTable')) {
21 | $timestamp = date('Y_m_d_His', time());
22 |
23 | $this->publishes([
24 | __DIR__.'/../database/migrations/create_statuses_table.php.stub' => database_path("migrations/{$timestamp}_create_statuses_table.php"),
25 | ], 'migrations');
26 | }
27 |
28 | $this->publishes([
29 | __DIR__.'/../config/status.php' => config_path('status.php'),
30 | ], 'config');
31 | }
32 |
33 | /**
34 | * Register any application services.
35 | *
36 | * @return void
37 | */
38 | public function register()
39 | {
40 | if (config('status.enable_events', true)) {
41 | $this->app->register(EventServiceProvider::class);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Status.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | protected $fillable = [
24 | 'name', 'model_type', 'is_default',
25 | ];
26 |
27 | /**
28 | * The attributes that should be visible in arrays.
29 | *
30 | * @var array
31 | */
32 | protected $visible = ['name'];
33 |
34 | /**
35 | * Get default status from model.
36 | *
37 | * @param class-string<\Illuminate\Database\Eloquent\Model> $modelClass
38 | * @param string|array $column
39 | *
40 | * @return mixed
41 | *
42 | * @deprecated Removing this method on next major release of "skore-labs/laravel-status"
43 | */
44 | public static function getDefault($modelClass, $column = 'id')
45 | {
46 | /** @var \Illuminate\Database\Eloquent\Builder<\SkoreLabs\LaravelStatus\Status> $baseQuery */
47 | $baseQuery = self::where('model_type', $modelClass);
48 |
49 | $query = $baseQuery->where('is_default', true);
50 |
51 | if (!$query->exists()) {
52 | $query = $baseQuery;
53 | }
54 |
55 | if (is_array($column)) {
56 | return $query->first($column);
57 | }
58 |
59 | return $query->value($column);
60 | }
61 |
62 | /**
63 | * Get column from status enum class.
64 | *
65 | * @param \Spatie\Enum\Enum $enum
66 | * @param \Illuminate\Database\Eloquent\Model $from
67 | * @param string|array $column
68 | *
69 | * @return \Illuminate\Database\Eloquent\Model|object|\Illuminate\Database\Eloquent\Builder|null|mixed
70 | */
71 | public static function getFromEnum(Enum $enum, Model $from, $column = 'id')
72 | {
73 | $fromModelMorphClass = $from->getMorphClass();
74 |
75 | $query = self::query()
76 | ->where('model_type', $fromModelMorphClass)
77 | ->where('name', 'like', "%{$enum->label}%");
78 |
79 | if ($query->count('id') === 0) {
80 | $query->orWhere(function (Builder $query) use ($fromModelMorphClass) {
81 | $query->defaultFrom($fromModelMorphClass);
82 | });
83 | }
84 |
85 | return is_array($column)
86 | ? $query->first($column)
87 | : $query->value($column);
88 | }
89 |
90 | /**
91 | * Wrap status value into status enum class.
92 | *
93 | * @param mixed|\Spatie\Enum\Enum $class
94 | * @param mixed $value
95 | *
96 | * @return \Spatie\Enum\Enum|false
97 | */
98 | public static function toEnum($class, $value)
99 | {
100 | if (!$value || !method_exists($class, 'tryFrom')) {
101 | return false;
102 | }
103 |
104 | if (!($value instanceof Enum)) {
105 | return $class::tryFrom($value);
106 | }
107 |
108 | return $value;
109 | }
110 |
111 | /**
112 | * Create a new Eloquent query builder for the model.
113 | *
114 | * @param \Illuminate\Database\Query\Builder $query
115 | *
116 | * @return \SkoreLabs\LaravelStatus\StatusBuilder
117 | */
118 | public function newEloquentBuilder($query)
119 | {
120 | return new StatusBuilder($query);
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/StatusBuilder.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class StatusBuilder extends Builder
12 | {
13 | /**
14 | * Get default status from model.
15 | *
16 | * @param string|\Illuminate\Database\Eloquent\Model $modelType
17 | *
18 | * @return $this
19 | */
20 | public function defaultFrom($modelType)
21 | {
22 | $this->where(function (self $query) use ($modelType) {
23 | $query->where(
24 | 'model_type',
25 | $modelType instanceof Model
26 | ? $modelType->getMorphClass()
27 | : $modelType
28 | );
29 |
30 | $query->where('is_default', true);
31 | });
32 |
33 | return $this;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Traits/HasStatuses.php:
--------------------------------------------------------------------------------
1 | fillable = array_merge($this->fillable, ['status']);
40 | $this->guarded = array_merge($this->guarded, ['status_id']);
41 |
42 | if (config('status.enable_events', true)) {
43 | $this->addObservableEvents($this->getStatusObservables());
44 |
45 | static::saving(function () {
46 | if ($this->savingStatus) {
47 | $this->savingStatus = false;
48 | $this->fireModelEvent('saved'.$this->formatStatusName($this->getStatus()), false);
49 | }
50 | });
51 | }
52 | }
53 |
54 | /**
55 | * Get the statuses enum used for some utilities.
56 | *
57 | * @return string|\Spatie\Enum\Enum
58 | */
59 | public static function statusesClass()
60 | {
61 | return config('status.enums_path').class_basename(self::class).'Status';
62 | }
63 |
64 | /**
65 | * Get statuses custom observables events.
66 | *
67 | * @return array
68 | */
69 | protected function getStatusObservables()
70 | {
71 | $statusEventsArr = [];
72 | $statuses = static::getStatuses();
73 |
74 | foreach ($statuses as $status) {
75 | $status = $this->formatStatusName($status);
76 |
77 | $statusEventsArr[] = "saving${status}";
78 | $statusEventsArr[] = "saved${status}";
79 | }
80 |
81 | return $statusEventsArr;
82 | }
83 |
84 | /**
85 | * Get or set current status for this model.
86 | *
87 | * @param bool $value
88 | *
89 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo|string|bool
90 | */
91 | public function status($value = false)
92 | {
93 | if ($value) {
94 | return is_array($value) && Arr::isAssoc($value)
95 | ? $this->setStatus($value)
96 | : $this->hasStatus($value);
97 | }
98 |
99 | return $this->belongsTo(
100 | config('status.use_model', Status::class)
101 | );
102 | }
103 |
104 | /**
105 | * Get statuses available for this model as attribute.
106 | *
107 | * @return array
108 | */
109 | public function getStatusesAttribute()
110 | {
111 | return static::getStatuses();
112 | }
113 |
114 | /**
115 | * Get statuses available for this model.
116 | *
117 | * @return array
118 | */
119 | public static function getStatuses()
120 | {
121 | return static::statusesClass()::toValues();
122 | }
123 |
124 | /**
125 | * Set status by label(s) to key and perform a save.
126 | *
127 | * @param array|string|\Spatie\Enum\Enum $name
128 | *
129 | * @return bool
130 | */
131 | public function setStatus($name = null)
132 | {
133 | if (is_array($name) && !empty($name) && Arr::isAssoc($name)) {
134 | return $this->setStatusWhen(array_key_first($name), head($name));
135 | }
136 |
137 | if (empty($name) || is_null($name) || $this->hasStatus($name)) {
138 | return false;
139 | }
140 |
141 | $this->setStatusAttribute($name);
142 |
143 | if (!$this->savingStatus) {
144 | return false;
145 | }
146 |
147 | return $this->save();
148 | }
149 |
150 | /**
151 | * Set status when current status is.
152 | *
153 | * @param mixed $current
154 | * @param mixed $new
155 | *
156 | * @return bool
157 | */
158 | public function setStatusWhen($current, $new)
159 | {
160 | if (!$this->hasStatus($current) || $this->hasStatus($new)) {
161 | return false;
162 | }
163 |
164 | $this->setStatusAttribute($new);
165 |
166 | return $this->save();
167 | }
168 |
169 | /**
170 | * Set status relation as attribute.
171 | *
172 | * @param string|\Spatie\Enum\Enum $value
173 | *
174 | * @return void
175 | */
176 | public function setStatusAttribute($value = null)
177 | {
178 | if (!$value) {
179 | return;
180 | }
181 |
182 | $eventName = $this->formatStatusName($value instanceof Enum ? $value->value : $value);
183 |
184 | $this->savingStatus = $this->fireModelEvent("saving${eventName}") !== false;
185 |
186 | $this->status()->associate(
187 | $this->status()->getModel()::getFromEnum($this->toStatusEnum($value), $this)
188 | );
189 | }
190 |
191 | /**
192 | * Check current status is equals to.
193 | *
194 | * @param string|array|\Spatie\Enum\Enum $value
195 | *
196 | * @return bool
197 | */
198 | public function hasStatus($value)
199 | {
200 | $enumFromStatusInstance = $this->toStatusEnum(
201 | $this->getStatus() ?: $this->getDefaultStatus()
202 | );
203 |
204 | return Collection::make((array) $value)->map(function ($item) {
205 | return $this->toStatusEnum($item);
206 | })->filter()->every(function ($item) use ($enumFromStatusInstance) {
207 | return $enumFromStatusInstance->equals($item);
208 | });
209 | }
210 |
211 | /**
212 | * Transform status string value to enum object.
213 | *
214 | * @param mixed $value
215 | *
216 | * @return \Spatie\Enum\Enum|false
217 | */
218 | protected function toStatusEnum($value)
219 | {
220 | /** @var \SkoreLabs\LaravelStatus\Status $statusModel */
221 | $statusModel = $this->status()->getModel();
222 |
223 | return $statusModel::toEnum(
224 | static::statusesClass(),
225 | is_string($value) ? Str::camel($value) : $value
226 | );
227 | }
228 |
229 | /**
230 | * Get model status or default instead.
231 | *
232 | * @param string $column
233 | *
234 | * @return string|null
235 | */
236 | public function getStatus($column = 'name')
237 | {
238 | return $this->status()->value($column);
239 | }
240 |
241 | /**
242 | * Get default status for this model.
243 | *
244 | * @param string|array $column
245 | *
246 | * @return \Illuminate\Database\Eloquent\Model|object|\Illuminate\Database\Eloquent\Builder|null|mixed
247 | */
248 | public static function getDefaultStatus($column = 'name')
249 | {
250 | $modelInstance = new static();
251 |
252 | return $modelInstance->status()->getModel()
253 | ->query()
254 | ->defaultFrom($modelInstance)
255 | ->value($column);
256 | }
257 |
258 | /**
259 | * List all resources of a specified status.
260 | *
261 | * @param \Illuminate\Database\Eloquent\Builder $query
262 | * @param string|\Spatie\Enum\Enum $name
263 | *
264 | * @return \Illuminate\Database\Eloquent\Builder
265 | */
266 | public function scopeStatus(Builder $query, $name)
267 | {
268 | return $query->whereHas('status', function (Builder $query) use ($name) {
269 | $query->where('name', 'like', $name instanceof Enum ? $name->label : $name);
270 | });
271 | }
272 |
273 | /**
274 | * List all resources of an array of statuses.
275 | *
276 | * @param \Illuminate\Database\Eloquent\Builder $query
277 | * @param array|array<\Spatie\Enum\Enum> $statuses
278 | *
279 | * @return void
280 | */
281 | public function scopeStatuses(Builder $query, array $statuses)
282 | {
283 | return $query->whereHas('status', function (Builder $query) use ($statuses) {
284 | $i = 0;
285 |
286 | foreach ($statuses as $status) {
287 | $query->where('name', 'like', $status instanceof Enum ? $status->label : $status, $i === 0 ? 'and' : 'or');
288 | $i++;
289 | }
290 | });
291 | }
292 |
293 | /**
294 | * Get status name capitalised.
295 | *
296 | * @param string|array|null $name
297 | *
298 | * @return string|string[]|false
299 | */
300 | protected function formatStatusName($name = null)
301 | {
302 | if (!$name) {
303 | return false;
304 | }
305 |
306 | $replaceStrFn = static function ($name) {
307 | return str_replace(' ', '', ucwords($name));
308 | };
309 |
310 | return is_array($name) ? array_map($replaceStrFn, $name) : $replaceStrFn($name);
311 | }
312 | }
313 |
--------------------------------------------------------------------------------
/tests/Fixtures/AnotherStatuses.php:
--------------------------------------------------------------------------------
1 | status->name)
50 | ->equals(static::statusesClass()::published());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tests/Fixtures/PostStatuses.php:
--------------------------------------------------------------------------------
1 | PostStatuses::toValues(),
25 | ])->each(function ($names, $modelType) {
26 | foreach ($names as $name) {
27 | Status::create([
28 | 'name' => $name,
29 | 'model_type' => $modelType,
30 | 'is_default' => array_search($name, $names, true) === 0,
31 | ]);
32 | }
33 | });
34 | }
35 |
36 | public function test_status_assignment()
37 | {
38 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
39 | $post = Post::make()->forceFill([
40 | 'title' => $this->faker->words(3, true),
41 | 'content' => $this->faker->paragraph(),
42 | ]);
43 |
44 | $post->status = 'published';
45 | $post->save();
46 |
47 | $this->assertFalse($post->isDirty(), 'Model::status($value) should associate + save (persisting)');
48 |
49 | $this->assertEquals(
50 | PostStatuses::published()->label,
51 | $post->status->name,
52 | 'Model status should be the one previously assigned: "published"'
53 | );
54 |
55 | $this->assertTrue(
56 | $post->hasStatus('pUbliShed') && $post->status(['pUbLished']),
57 | 'Model::hasStatus($name) & Model::status([$name, ...]) methods should work'
58 | );
59 |
60 | $this->assertFalse(
61 | $post->hasStatus(['draft', 'archiVed']),
62 | 'Model::hasStatus([$name, ...]) method shouldn\'t return true when array of statuses doesn\'t match the current "published"'
63 | );
64 |
65 | $this->assertTrue(
66 | $post->hasStatus(PostStatuses::published()),
67 | 'Model::hasStatus($enum) method should also work with enums'
68 | );
69 | }
70 |
71 | public function test_status_conditional_assignment()
72 | {
73 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
74 | $post = Post::make()->forceFill([
75 | 'title' => $this->faker->words(3, true),
76 | 'content' => $this->faker->paragraph(),
77 | ]);
78 |
79 | $post->status = 'published';
80 | $post->save();
81 |
82 | $this->assertEquals(PostStatuses::published(), $post->status->name);
83 |
84 | $this->assertFalse($post->status(['archived' => 'draft']));
85 |
86 | $this->assertEquals(PostStatuses::published(), $post->status->name);
87 |
88 | $this->assertTrue($post->status(['published' => 'draft']));
89 |
90 | $this->assertEquals(PostStatuses::draft(), $post->status->name);
91 | }
92 |
93 | public function test_model_status_default_assignation()
94 | {
95 | $this->markTestIncomplete('How can we make this working?');
96 |
97 | Event::fake();
98 |
99 | Event::assertListening(
100 | StatusCreating::class,
101 | AttachDefaultStatus::class
102 | );
103 |
104 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
105 | $post = Post::make()->forceFill([
106 | 'title' => $this->faker->words(3, true),
107 | 'content' => $this->faker->paragraph(),
108 | ]);
109 |
110 | $this->assertEmpty(
111 | optional($post->status)->name,
112 | 'When model isn\'t created yet, shouldn\'t have a status'
113 | );
114 |
115 | $post->save();
116 |
117 | Event::assertDispatched(StatusCreating::class, function (StatusCreating $event) use ($post) {
118 | return $event->model->is($post)
119 | && $event->model->getDefaultStatus() === optional($event->model->status)->name;
120 | });
121 | }
122 |
123 | public function test_status_model_methods()
124 | {
125 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
126 | $post = Post::make()->forceFill([
127 | 'title' => $this->faker->words(3, true),
128 | 'content' => $this->faker->paragraph(),
129 | ]);
130 |
131 | $this->assertEquals(
132 | PostStatuses::draft(),
133 | Status::defaultFrom($post)->value('name'),
134 | 'Status::defaultFrom($model) should get the default status for $model which is "draft"'
135 | );
136 |
137 | // TODO: Remove this once is fully deprecated
138 | $this->assertEquals(
139 | PostStatuses::draft(),
140 | Status::getDefault($post->getMorphClass(), 'name'),
141 | 'Status::defaultFrom($model) should get the default status for $model which is "draft"'
142 | );
143 |
144 | $this->assertEquals(
145 | PostStatuses::draft(),
146 | Status::getFromEnum(AnotherStatuses::abc(), $post, 'name'),
147 | 'Status::getFromEnum($enum, $model, \'name\') when enum & model instances doesn\'t match must return "draft"'
148 | );
149 |
150 | $post->setStatus(PostStatuses::published());
151 |
152 | $this->assertEquals(
153 | PostStatuses::published()->value,
154 | Status::getFromEnum(PostStatuses::published(), $post, 'name'),
155 | 'Status::getFromEnum($enum, $model, \'name\') published from posts must return "published"'
156 | );
157 |
158 | $this->assertTrue(
159 | Status::where('name', (string) PostStatuses::published())->first(['*'])->is(
160 | Status::getFromEnum(PostStatuses::published(), $post, ['*'])
161 | ),
162 | 'Status::getFromEnum($enum, $model, [\'*\']) must return a whole "Status" model result'
163 | );
164 | }
165 |
166 | public function test_status_to_enum()
167 | {
168 | $this->assertEquals(
169 | Post::statusesClass()::published(),
170 | Status::toEnum(Post::statusesClass(), 'published')
171 | );
172 |
173 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
174 | $post = Post::make()->forceFill([
175 | 'title' => $this->faker->words(3, true),
176 | 'content' => $this->faker->paragraph(),
177 | ]);
178 |
179 | $mock = $this->mock(Post::class)->shouldAllowMockingProtectedMethods();
180 |
181 | $mock->shouldReceive('toStatusEnum')
182 | ->andReturn(PostStatuses::published());
183 |
184 | $post->setStatus('published');
185 |
186 | $this->assertEquals(PostStatuses::published()->label, $post->getStatus());
187 |
188 | $mock->shouldReceive('toStatusEnum')
189 | ->withSomeOfArgs($post->getStatus(), 'draft', 'archived')
190 | ->andReturnValues([PostStatuses::published(), PostStatuses::draft(), PostStatuses::archived()]);
191 |
192 | $this->assertFalse($post->hasStatus(['draft', 'archived']));
193 | }
194 |
195 | public function test_status_assignments_with_enums()
196 | {
197 | /** @var \SkoreLabs\LaravelStatus\Tests\Fixtures\Post $post */
198 | $post = Post::make()->forceFill([
199 | 'title' => $this->faker->words(3, true),
200 | 'content' => $this->faker->paragraph(),
201 | ]);
202 |
203 | $post->setStatus(PostStatuses::archived());
204 |
205 | $this->assertFalse($post->isDirty());
206 |
207 | $this->assertEquals(
208 | PostStatuses::archived()->label,
209 | $post->status->name
210 | );
211 |
212 | $post->setStatusWhen(PostStatuses::draft(), PostStatuses::published());
213 |
214 | $this->assertEquals(
215 | PostStatuses::archived()->label,
216 | $post->status->name
217 | );
218 |
219 | $post->setStatusWhen(PostStatuses::archived(), PostStatuses::published());
220 |
221 | $this->assertEquals(
222 | PostStatuses::published()->label,
223 | $post->status->name
224 | );
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | up();
22 | }
23 |
24 | /**
25 | * Load package service provider.
26 | *
27 | * @param \Illuminate\Foundation\Application $app
28 | *
29 | * @return array
30 | */
31 | protected function getPackageProviders($app)
32 | {
33 | return [
34 | 'SkoreLabs\LaravelStatus\ServiceProvider',
35 | ];
36 | }
37 |
38 | /**
39 | * Define environment setup.
40 | *
41 | * @param \Illuminate\Foundation\Application $app
42 | *
43 | * @return void
44 | */
45 | protected function defineEnvironment($app)
46 | {
47 | // Setup default database to use sqlite :memory:
48 | $app['config']->set('database.default', 'testing');
49 | $app['config']->set('database.connections.testing', [
50 | 'driver' => 'sqlite',
51 | 'database' => ':memory:',
52 | 'prefix' => '',
53 | ]);
54 |
55 | // Setup package own config (statuses)
56 | $app['config']->set('status', include_once __DIR__.'/../config/status.php');
57 | }
58 |
59 | /**
60 | * Define database migrations.
61 | *
62 | * @return void
63 | */
64 | protected function defineDatabaseMigrations()
65 | {
66 | $this->loadMigrationsFrom(__DIR__.'/database');
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/database/0000_00_00_000000_create_posts_test_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
13 | $table->unsignedBigInteger('status_id')->nullable();
14 | $table->string('title');
15 | $table->text('content');
16 | $table->timestamps();
17 | });
18 |
19 | Schema::table('posts', function (Blueprint $table) {
20 | $table->foreign('status_id')
21 | ->references('id')
22 | ->on('statuses')
23 | ->onDelete('cascade');
24 | });
25 | }
26 |
27 | public function down()
28 | {
29 | Schema::dropIfExists('posts');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------