Skip to content

Commit c2b110a

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/scheduled-drafts
2 parents 8ea1627 + 0dbd0f7 commit c2b110a

20 files changed

+344
-47
lines changed

.github/FUNDING.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# These are supported funding model platforms
2+
3+
github: oddvalue

.github/workflows/run-tests.yml

+9-4
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@ jobs:
1212
strategy:
1313
fail-fast: true
1414
matrix:
15-
os: [ubuntu-latest, windows-latest]
16-
php: [8.0,8.1]
17-
laravel: [9.*]
18-
stability: [prefer-lowest, prefer-stable]
15+
os: [ubuntu-latest]
16+
php: [8.0,8.1,8.2]
17+
laravel: [9.*,10.*]
18+
stability: [prefer-stable]
1919
include:
2020
- laravel: 9.*
2121
testbench: 7.*
22+
- laravel: 10.*
23+
testbench: 8.*
24+
exclude:
25+
- php: 8.0
26+
laravel: 10.*
2227

2328
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
2429

CHANGELOG.md

+25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
All notable changes to `laravel-drafts` will be documented in this file.
44

5+
## v1.2.0 - 2023-02-22
6+
7+
### What's Changed
8+
9+
- New feature: preview mode by @oddvalue in https://github.com/oddvalue/laravel-drafts/pull/19
10+
- Add support for Laravel 10 by @oddvalue in https://github.com/oddvalue/laravel-drafts/pull/20
11+
12+
**Full Changelog**: https://github.com/oddvalue/laravel-drafts/compare/v1.1.0...v1.2.0
13+
14+
## v1.1.0 - 2023-02-20
15+
16+
### What's Changed
17+
18+
- Added a method to avoid creating revison by @Froxz in https://github.com/oddvalue/laravel-drafts/pull/15
19+
20+
### New Contributors
21+
22+
- @Froxz made their first contribution in https://github.com/oddvalue/laravel-drafts/pull/15
23+
24+
**Full Changelog**: https://github.com/oddvalue/laravel-drafts/compare/v1.0.2...v1.1.0
25+
26+
## v1.0.2 - 2023-02-17
27+
28+
**Full Changelog**: https://github.com/oddvalue/laravel-drafts/compare/v1.0.1...v1.0.2
29+
530
## v0.0.3 - 2022-07-01
631

732
**Full Changelog**: https://github.com/oddvalue/laravel-drafts/compare/v0.0.2...v0.0.3

README.md

+40-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
+ [Interacting with records](#interacting-with-records)
2222
- [Published revision](#published-revision)
2323
- [Current Revision](#current-revision)
24+
- [Revisions](#revisions)
25+
- [Preview mode](#preview-mode)
2426
* [Testing](#testing)
2527
* [Changelog](#changelog)
2628
* [Contributing](#contributing)
@@ -248,8 +250,6 @@ To fetch the current revision you can call the `current` scope.
248250
$posts = Post::current()->get();
249251
```
250252

251-
You can implement a preview mode for your frontend by calling the `current` scope when fetching records.
252-
253253
#### Revisions
254254

255255
Every time a record is updated a new row/revision will be inserted. The default number of revisions kept is 10, this can be updated in the published config file.
@@ -263,6 +263,44 @@ $revisions = $post->revisions();
263263

264264
Deleting a record will also delete all of its revisions. Soft deleting records will soft delete the revisions and restoring records will restore the revisions.
265265

266+
If you need to update a record without creating revision
267+
268+
```php
269+
$post->withoutRevision()->update($options);
270+
```
271+
272+
#### Preview Mode
273+
274+
Enabling preview mode will disable the global scope that fetches only published records and will instead fetch the current revision regardless of published state.
275+
276+
```php
277+
# Enable preview mode
278+
\Oddvalue\LaravelDrafts\Facades\LaravelDrafts::previewMode();
279+
\Oddvalue\LaravelDrafts\Facades\LaravelDrafts::previewMode(true);
280+
281+
# Disable preview mode
282+
\Oddvalue\LaravelDrafts\Facades\LaravelDrafts::disablePreviewMode();
283+
\Oddvalue\LaravelDrafts\Facades\LaravelDrafts::previewMode(false);
284+
```
285+
286+
### Middleware
287+
288+
#### WithDraftsMiddleware
289+
290+
If you require a specific route to be able to access drafts then you can use the `WithDraftsMiddleware` middleware.
291+
292+
```php
293+
Route::get('/posts/publish/{post}', [PostController::class, 'publish'])->middleware(\Oddvalue\LaravelDrafts\Http\Middleware\WithDraftsMiddleware::class);
294+
```
295+
296+
There is also a helper method on the router that allows you to create a group with that middleware applied.
297+
298+
```php
299+
Route::withDrafts(function (): void {
300+
Route::get('/posts/publish/{post}', [PostController::class, 'publish']);
301+
});
302+
```
303+
266304
## Testing
267305

268306
```bash

composer.json

+5-7
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,22 @@
1919
"require": {
2020
"php": "^8.0",
2121
"doctrine/dbal": "^3.3",
22-
"illuminate/contracts": "^9.0",
22+
"illuminate/contracts": "^9.0|^10.0",
2323
"spatie/laravel-package-tools": "^1.9.2"
2424
},
2525
"require-dev": {
26-
"roave/security-advisories": "dev-latest",
2726
"friendsofphp/php-cs-fixer": "^3.8",
2827
"nunomaduro/collision": "^6.0",
2928
"nunomaduro/larastan": "^2.0.1",
30-
"orchestra/testbench": "^7.0",
29+
"orchestra/testbench": "^7.0|^8.0",
3130
"pestphp/pest": "^1.21",
32-
"pestphp/pest-plugin-laravel": "^1.1",
33-
"pestphp/pest-plugin-parallel": "^1.2",
31+
"pestphp/pest-plugin-laravel": "^1.1|^2.0",
3432
"phpstan/extension-installer": "^1.1",
3533
"phpstan/phpstan-deprecation-rules": "^1.0",
3634
"phpstan/phpstan-phpunit": "^1.0",
3735
"phpunit/phpunit": "^9.5",
38-
"spatie/laravel-ray": "^1.26",
39-
"spatie/pest-plugin-test-time": "^1.1"
36+
"spatie/pest-plugin-test-time": "^1.1",
37+
"roave/security-advisories": "dev-latest"
4038
},
4139
"autoload": {
4240
"psr-4": {

src/Concerns/HasDrafts.php

+61-19
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,20 @@ public function initializeHasDrafts(): void
3939
{
4040
$this->mergeCasts([
4141
$this->getIsCurrentColumn() => 'boolean',
42+
$this->getIsPublishedColumn() => 'boolean',
4243
$this->getPublishedAtColumn() => 'datetime',
4344
]);
4445
}
4546

4647
public static function bootHasDrafts(): void
4748
{
48-
static::creating(function (Draftable | Model $model) {
49+
static::addGlobalScope('onlyCurrentInPreviewMode', static function (Builder $builder): void {
50+
if (LaravelDrafts::isPreviewModeEnabled()) {
51+
$builder->current();
52+
}
53+
});
54+
55+
static::creating(function (Draftable | Model $model): void {
4956
$model->{$model->getIsCurrentColumn()} = true;
5057
$model->setPublisher();
5158
$model->generateUuid();
@@ -54,26 +61,26 @@ public static function bootHasDrafts(): void
5461
}
5562
});
5663

57-
static::updating(function (Draftable | Model $model) {
64+
static::updating(function (Draftable | Model $model): void {
5865
$model->newRevision();
5966
});
6067

61-
static::publishing(function (Draftable | Model $model) {
68+
static::publishing(function (Draftable | Model $model): void {
6269
$model->setLive();
6370
});
6471

65-
static::deleted(function (Draftable | Model $model) {
72+
static::deleted(function (Draftable | Model $model): void {
6673
$model->revisions()->delete();
6774
});
6875

6976
if (method_exists(static::class, 'restored')) {
70-
static::restored(function (Draftable | Model $model) {
77+
static::restored(function (Draftable | Model $model): void {
7178
$model->revisions()->restore();
7279
});
7380
}
7481

7582
if (method_exists(static::class, 'forceDeleted')) {
76-
static::forceDeleted(function (Draftable | Model $model) {
83+
static::forceDeleted(function (Draftable | Model $model): void {
7784
$model->revisions()->forceDelete();
7885
});
7986
}
@@ -96,7 +103,11 @@ protected function newRevision(): void
96103

97104
$revision = $this->fresh()?->replicate();
98105

99-
static::saved(function () use ($revision) {
106+
static::saved(function (Model $model) use ($revision): void {
107+
if ($model->isNot($this)) {
108+
return;
109+
}
110+
100111
$revision->created_at = $this->created_at;
101112
$revision->updated_at = $this->updated_at;
102113
$revision->is_current = false;
@@ -111,6 +122,13 @@ protected function newRevision(): void
111122
});
112123
}
113124

125+
public function withoutRevision(): static
126+
{
127+
$this->shouldCreateRevision = false;
128+
129+
return $this;
130+
}
131+
114132
public function shouldCreateRevision(): bool
115133
{
116134
return $this->shouldCreateRevision;
@@ -124,26 +142,33 @@ public function generateUuid(): void
124142
$this->{$this->getUuidColumn()} = Str::uuid();
125143
}
126144

145+
public function getDraftableAttributes(): array
146+
{
147+
return $this->getAttributes();
148+
}
149+
127150
public function setCurrent(): void
128151
{
129152
$oldCurrent = $this->revisions()->withDrafts()->current()->excludeRevision($this)->first();
130153

131-
static::saved(function () use ($oldCurrent) {
132-
if ($oldCurrent) {
133-
$oldCurrent->{$this->getIsCurrentColumn()} = false;
134-
$oldCurrent->timestamps = false;
135-
$oldCurrent->saveQuietly();
154+
static::saved(function (Model $model) use ($oldCurrent): void {
155+
if ($model->isNot($this) || ! $oldCurrent) {
156+
return;
136157
}
158+
159+
$oldCurrent->{$this->getIsCurrentColumn()} = false;
160+
$oldCurrent->timestamps = false;
161+
$oldCurrent->saveQuietly();
137162
});
138163

139164
$this->{$this->getIsCurrentColumn()} = true;
140165
}
141166

142167
public function setLive(): void
143168
{
144-
$published = $this->revisions()->excludeRevision($this)->published()->first();
169+
$published = $this->revisions()->published()->first();
145170

146-
if (! $published) {
171+
if (! $published || $this->is($published)) {
147172
$this->{$this->getPublishedAtColumn()} ??= now();
148173
$this->{$this->getWillPublishAtColumn()} = null;
149174
$this->{$this->getIsPublishedColumn()} = true;
@@ -152,15 +177,19 @@ public function setLive(): void
152177
return;
153178
}
154179

155-
$oldAttributes = $published?->getAttributes() ?? [];
156-
$newAttributes = $this->getAttributes();
180+
$oldAttributes = $published?->getDraftableAttributes() ?? [];
181+
$newAttributes = $this->getDraftableAttributes();
157182
Arr::forget($oldAttributes, $this->getKeyName());
158183
Arr::forget($newAttributes, $this->getKeyName());
159184

160185
$published->forceFill($newAttributes);
161186
$this->forceFill($oldAttributes);
162187

163-
static::saved(function () use ($published) {
188+
static::saved(function (Model $model) use ($published): void {
189+
if ($model->isNot($this)) {
190+
return;
191+
}
192+
164193
$published->{$this->getIsPublishedColumn()} = true;
165194
$published->{$this->getPublishedAtColumn()} ??= now();
166195
$published->setCurrent();
@@ -171,13 +200,21 @@ public function setLive(): void
171200
switch (true) {
172201
case $relation instanceof HasOne:
173202
if ($related = $this->{$relationName}) {
174-
$published->{$relationName}()->create($related->replicate()->getAttributes());
203+
$replicated = $related->replicate();
204+
205+
$method = method_exists($replicated, 'getDraftableAttributes') ? 'getDraftableAttributes' : 'getAttributes';
206+
207+
$published->{$relationName}()->create($replicated->$method());
175208
}
176209

177210
break;
178211
case $relation instanceof HasMany:
179212
$this->{$relationName}()->get()->each(function ($model) use ($published, $relationName) {
180-
$published->{$relationName}()->create($model->replicate()->getAttributes());
213+
$replicated = $model->replicate();
214+
215+
$method = method_exists($replicated, 'getDraftableAttributes') ? 'getDraftableAttributes' : 'getAttributes';
216+
217+
$published->{$relationName}()->create($replicated->$method());
181218
});
182219

183220
break;
@@ -250,6 +287,11 @@ public function shouldDraft(): bool
250287
return $this->shouldSaveAsDraft;
251288
}
252289

290+
public function setPublishedAttribute(): void
291+
{
292+
// Do nothing, everything should be handled by `setLive`
293+
}
294+
253295
public function save(array $options = []): bool
254296
{
255297
if (

src/Concerns/Publishes.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Oddvalue\LaravelDrafts\Concerns;
44

55
use Closure;
6+
use Illuminate\Database\Eloquent\Model;
67
use Oddvalue\LaravelDrafts\Scopes\PublishingScope;
78

89
/**
@@ -31,16 +32,25 @@ public function publish(): static
3132
return $this;
3233
}
3334

34-
$this->{$this->getPublishedAtColumn()} ??= now();
35-
$this->{$this->getIsPublishedColumn()} = true;
35+
$this->setPublishedAttributes();
36+
37+
static::saved(function (Model $model): void {
38+
if ($model->isNot($this)) {
39+
return;
40+
}
3641

37-
static::saved(function () {
3842
$this->fireModelEvent('published');
3943
});
4044

4145
return $this;
4246
}
4347

48+
protected function setPublishedAttributes(): void
49+
{
50+
$this->{$this->getPublishedAtColumn()} ??= now();
51+
$this->{$this->getIsPublishedColumn()} = true;
52+
}
53+
4454
public function isPublished(): bool
4555
{
4656
return $this->{$this->getIsPublishedColumn()} ?? false;

src/Facades/LaravelDrafts.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@
77
use Illuminate\Support\Facades\Facade;
88

99
/**
10+
* @method static \Illuminate\Contracts\Auth\Authenticatable getCurrentUser()
11+
* @method static void previewMode(bool $previewMode = true)
12+
* @method static void disablePreviewMode()
13+
* @method static bool isPreviewModeEnabled()
14+
* @method static void withDrafts(bool $withDrafts = true)
15+
* @method static bool isWithDraftsEnabled()
16+
*
1017
* @see \Oddvalue\LaravelDrafts\LaravelDrafts
1118
* @method Model | Authenticatable getCurrentUser();
1219
*/
1320
class LaravelDrafts extends Facade
1421
{
1522
protected static function getFacadeAccessor(): string
1623
{
17-
return 'laravel-drafts';
24+
return \Oddvalue\LaravelDrafts\LaravelDrafts::class;
1825
}
1926
}

0 commit comments

Comments
 (0)