-
-
Notifications
You must be signed in to change notification settings - Fork 33
Add soft delete observable events #224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
45d0748
0f2b4c4
c9e9095
0c9dbc5
bf4762e
d66cc3f
43ba814
dfc23f7
28c0ec6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -231,6 +231,34 @@ public function isLocalDisk(\Illuminate\Filesystem\FilesystemAdapter $disk): boo | |
| return ($disk->getAdapter() instanceof \League\Flysystem\Local\LocalFilesystemAdapter); | ||
| } | ||
|
|
||
| /** | ||
| * Apply a unique index to a filename from provided list i.e. | ||
| * winter.txt, [winter_1.txt, winter_2.txt] -> winter_3.txt | ||
| * winter.txt, [winter_1.txt, winter_3.txt] -> winter_4.txt | ||
| */ | ||
| public function unique(string $str, array $list, string $separator = '_', int $starting = 1, int $step = 1): string | ||
| { | ||
| $indexes = []; | ||
|
|
||
| $info = pathinfo($str); | ||
|
|
||
| if (empty($info['filename']) || empty($info['extension'])) { | ||
| throw new \InvalidArgumentException('$str must be a file name'); | ||
| } | ||
|
|
||
| foreach ($list as $item) { | ||
| if (!preg_match('/' . $info['filename'] . $separator . '(\d*)\.' . $info['extension'] . '/', $item, $matches)) { | ||
| continue; | ||
| } | ||
|
|
||
| $indexes[] = (int) $matches[1]; | ||
|
Comment on lines
+249
to
+254
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regex metacharacter injection and zero-length digit match Two correctness issues on the
🐛 Proposed fix- if (!preg_match('/' . $info['filename'] . $separator . '(\d*)\.' . $info['extension'] . '/', $item, $matches)) {
+ if (!preg_match(
+ '/^' . preg_quote($info['filename'], '/') . preg_quote($separator, '/') . '(\d+)\.' . preg_quote($info['extension'], '/') . '$/',
+ $item,
+ $matches
+ )) {Note: anchoring with 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| return empty($indexes) | ||
| ? $info['filename'] . $separator . $starting . '.' . $info['extension'] | ||
| : $info['filename'] . $separator . (max($indexes) + $step) . '.' . $info['extension']; | ||
| } | ||
|
|
||
| /** | ||
| * Finds the path of a given class. | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,27 @@ | |||||
| $this->filesystem = new Filesystem(); | ||||||
| } | ||||||
|
|
||||||
| public function testUnique() | ||||||
| { | ||||||
| $cases = [ | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHPCS: incorrect indentation The 🐛 Proposed fix- $cases = [
+ $cases = [📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Code Quality[error] 16-16: PHPCS: Line indented incorrectly; expected at least 8 spaces 🤖 Prompt for AI Agents |
||||||
| // File exists, make it unique | ||||||
| 'winter_1.cms' => ['winter.cms', ['winter.cms', 'test_5']], | ||||||
|
|
||||||
| // File already unique, return original | ||||||
| 'winter.cms' => ['winter.cms', ['winter_1.cms']], | ||||||
|
|
||||||
| // Last index available is incremented | ||||||
| 'winter_4.cms' => ['winter.cms', ['winter_1.cms', 'test_5', 'winter_3.cms']], | ||||||
| 'winter_98.cms' => ['winter.cms', ['winter_97.cms', 'test_5', 'winter_1.cms']], | ||||||
|
|
||||||
| // Separator as space | ||||||
| 'winter 1.cms' => ['winter.cms', ['winter_1.cms', 'test_5', 'winter_3.cms'], ' '], | ||||||
|
Comment on lines
+18
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test case 2's expected value causes the pipeline assertion failure The comment says "File already unique, return original", but the list Change the expected key to 🐛 Proposed fix (align test with implementation)- // File already unique, return original
- 'winter.cms' => ['winter.cms', ['winter_1.cms']],
+ // Next index when indexed versions already exist
+ 'winter_2.cms' => ['winter.cms', ['winter_1.cms']],🤖 Prompt for AI Agents |
||||||
| ]; | ||||||
| foreach ($cases as $output => $config) { | ||||||
| $this->assertSame($output, $this->filesystem->unique(...$config)); | ||||||
|
Check failure on line 31 in tests/Filesystem/FilesystemTest.php
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * @dataProvider providePathsForIsAbsolutePath | ||||||
| * @see Symfony\Component\Filesystem\Tests\FilesystemTest::testIsAbsolutePath | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forceDeletingandforceDeletedevents are never dispatched — registered callbacks will never fireThe two new registration methods correctly call
static::registerModelEvent(), but the Winter StormforceDelete()override (lines 90–97) only calls$this->delete()— which dispatchesdeleting/deleted— and never callsfireModelEvent('forceDeleting')orfireModelEvent('forceDeleted'). Laravel 9.x documentsforceDeletingandforceDeletedas distinct lifecycle events, fired explicitly by the framework's ownSoftDeletes::forceDelete(). Because Winter Storm overrides that method, it must replicate the event firing itself.Compare the existing
restore()method (lines 180, 193), which explicitly callsfireModelEvent('restoring')(halting) andfireModelEvent('restored', false)(non-halting). The same pattern must be applied toforceDelete().🐛 Proposed fix — fire the events in
forceDelete()public function forceDelete() { $this->forceDeleting = true; + if ($this->fireModelEvent('forceDeleting') === false) { + $this->forceDeleting = false; + return false; + } + $this->delete(); $this->forceDeleting = false; + + $this->fireModelEvent('forceDeleted', false); }🤖 Prompt for AI Agents