Feature/scheduled drafts - #11
Conversation
cddcd91 to
16fa512
Compare
8a79a76 to
84ba00a
Compare
16217c2 to
8527f0e
Compare
# Conflicts: # database/factories/PostFactory.php # src/Concerns/HasDrafts.php # src/Concerns/Publishes.php # src/Facades/LaravelDrafts.php # src/LaravelDrafts.php # src/LaravelDraftsServiceProvider.php # tests/ConfigTest.php # tests/RevisionsTest.php
The contract covers the stable consumer-facing draftable API and is satisfied by the HasDrafts trait. Implementing it on a model is optional but recommended, allowing user code to typehint against the contract. The drafts:publish command accepts models that either implement the contract or use the trait. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add UPGRADING.md covering enabling scheduled drafts and auto drafts on existing installations, plus a Rector rule (verified working) for adding the Draftable contract to existing models ahead of the future major that will require it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The heading-structure rule is configured Codacy-side for README-shaped files and does not fit an upgrade guide. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
oddvalue
left a comment
There was a problem hiding this comment.
The scheduled publishing implementation still has one contract mismatch that should be resolved before merging.
PublishScheduledDrafts::handle() accepts any class implementing Draftable, but the contract does not require scheduledDraftsEnabled(), newQuery(), or the onlyDrafts() scope. A contract-only implementation therefore passes the validation at src/Commands/PublishScheduledDrafts.php:25 and then fails at runtime.
Please either restrict the command to Eloquent models using HasDrafts, or expand the abstraction and remove the command's reliance on APIs that the contract does not guarantee.
I also found two scheduled-publishing defects and fixed them locally for follow-up: the live row retained will_publish_at after the draft/live attribute swap, and offset-based each() could skip due drafts beyond the first batch. Those changes have not been pushed.
Addresses review feedback on the contract mismatch: the Draftable contract doesn't guarantee scheduledDraftsEnabled(), newQuery() or the onlyDrafts() scope, so a contract-only implementation passed the command's validation and then failed at runtime. The command now requires an Eloquent model using the HasDrafts trait; the contract remains a consumer-facing typehint. Also includes the pre-existing local fixes: clear will_publish_at on the live row during the publish attribute swap, and use eachById so publishing is not skipped past the first batch, with regression tests for both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The stub's parameters are required by the Draftable interface. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The multi-batch regression test created 1001 records to cross the default eachById page size, taking ~29s. The command now accepts a --chunk option (default 1000), letting the test prove the same cross-batch behaviour with 3 records and a chunk of 2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
throw_if/throw_unless conversions, strict_types declares and formatting from the project Rector config. The Table/Fillable attribute conversion on the test Post model is excluded because those attributes require Laravel 12 and the test matrix still covers Laravel 11. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New rector.yml workflow running a dry-run on push, mirroring the PHPStan workflow - Skip the Table/Fillable attribute rules in rector.php since those attributes require Laravel 12 and the package supports Laravel 11 - Apply Rector to the remaining files so the dry-run passes repo-wide - Cover the previously untested paths: the getDraftableAttributes branch when replicating HasOne/HasMany relations, cancelling publish from a publishing listener, the base Publishes trait's setPublishedAttributes, and the deprecated withoutSelf scope Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rector-laravel 2.5 added Signature, Description and WithoutTimestamps attribute conversions. Those attributes require Laravel 12, and the package still supports Laravel 11, so skip them alongside the existing Table and Fillable exclusions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scheduled drafts
Adds the ability to schedule a draft to be published at a future date, revived from the original 2023 branch and reworked on top of current
main.Usage
Due drafts are published by the new artisan command, intended to run on the scheduler:
What's included
will_publish_attimestamp column, added by thedrafts()/dropDrafts()blueprint macros and overridable via config or aWILL_PUBLISH_ATmodel constantschedulePublishing(CarbonInterface $date)/clearScheduledPublishing()onHasDraftsdrafts:publish {model}command; publishing fires the usualpublishing/publishedevents, and publishing a draft directly clears any scheduled dateContracts\Draftableinterface covering the stable consumer-facing API. The trait satisfies it; implementing it is recommended and will become required in a future major.UPGRADING.mddocuments a tested Rector rule (AddInterfaceByTraitRector) that adds it to existing modelsUPGRADING.mdcovering enabling scheduled drafts and auto drafts on existing installationsMissingWillPublishAtColumnTestregression suite mirroring theis_autooneBackwards compatibility
Non-breaking; ships as a minor:
drafts.scheduled_drafts.enabled(defaultfalse), mirroring the auto drafts flag. While disabled no query references thewill_publish_atcolumn, so existing tables without it keep working; the scheduling API throws$table->drafts()from here on; upgrading installations add it manually before enabling (documented)Draftablecontract is optional and purely a consumer-facing typehint; thedrafts:publishcommand requires an Eloquent model using theHasDraftstraitChanges from the original branch
Draftableinterface insrc/Contacts/(namespace typo) in favour of a slim contract insrc/Contracts/that excludes internal plumbing, so future trait changes don't force interface breakspublish()instead of rawsetLive()so model events fire,eachById()so batches aren't skipped, and<=for the due-time comparison