Skip to content

Commit

Permalink
Add more attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
calebporzio committed May 8, 2023
1 parent a60fab2 commit 33bdf71
Show file tree
Hide file tree
Showing 20 changed files with 180 additions and 59 deletions.
5 changes: 4 additions & 1 deletion docs/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
## `wire:submit.prevent` no longer needed
- Change `wire:submit.prevent` to `wire:submit`

## Must now add #[Prop]
- Add `#[Prop]` to properties that inherit from the parent component

## QueryString
- Replace by default now, add "push" to keep the same
- "except" is no longer needed
Expand Down Expand Up @@ -50,7 +53,7 @@ use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
Route::prefix(LaravelLocalization::setLocale())
->group(function () {
... // Your other localized routes.

Livewire::setUpdateRoute(function ($handle) {
return Route::post('livewire/update', $handle);
});
Expand Down
35 changes: 17 additions & 18 deletions docs/uploads.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,19 @@ public function save()

// Store the uploaded file in the "photos" directory of the default filesystem disk.
$this->photo->store('photos');

// Store in the "photos" directory in a configured "s3" bucket.
$this->photo->store('photos', 's3');

// Store in the "photos" directory with the filename "avatar.png".
$this->photo->storeAs('photos', 'avatar');

// Store in the "photos" directory in a configured "s3" bucket with the filename "avatar.png".
$this->photo->storeAs('photos', 'avatar', 's3');

// Store in the "photos" directory, with "public" visibility in a configured "s3" bucket.
$this->photo->storePublicly('photos', 's3');

// Store in the "photos" directory, with the name "avatar.png", with "public" visibility in a configured "s3" bucket.
$this->photo->storePubliclyAs('photos', 'avatar', 's3');
}
Expand Down Expand Up @@ -132,7 +132,7 @@ Like you've seen previously, validating file uploads with Livewire is exactly th
For more information, visit [Laravel's file validation documentation](https://laravel.com/docs/validation#available-validation-rules).

### Real-time validation
### Real-time validation

It's possible to validate a user's upload in real-time, *before* they submit the form.

Expand Down Expand Up @@ -248,13 +248,13 @@ class UploadPhotoTest extends TestCase
public function can_upload_photo()
{
Storage::fake('avatars');

$file = UploadedFile::fake()->image('avatar.png');

Livewire::test(UploadPhoto::class)
->set('photo', $file)
->call('upload', 'uploaded-avatar.png');

Storage::disk('avatars')->assertExists('uploaded-avatar.png');
}
}
Expand Down Expand Up @@ -313,7 +313,7 @@ Now, when a user uploads a file, the file will never actually hit your server. I
> php artisan livewire:publish --config
> ```
### Configuring automatic file cleanup
### Configuring automatic file cleanup
This temporary directory will fill up with files quickly; therefore, it's important to configure S3 to cleanup files older than 24 hours.
Expand All @@ -325,10 +325,9 @@ php artisan livewire:configure-s3-upload-cleanup
Now, any temporary files older than 24 hours will be cleaned up by S3 automatically.
> [!tip]
> If you are not using S3, Livewire will handle the file cleanup automatically. No need to run this command.
## Loading indicators
## Loading indicators
Although `wire:model` for file uploads works differently than other `wire:model` input types under the hood, the interface for showing loading indicators remains the same.
Expand Down Expand Up @@ -370,7 +369,7 @@ Here is an example of wrapping a Livewire file upload in an AlpineJS component t
>
<!-- File Input -->
<input type="file" wire:model="photo">
<!-- Progress Bar -->
<div x-show="uploading">
<progress max="100" x-bind:value="progress"></progress>
Expand All @@ -381,7 +380,7 @@ Here is an example of wrapping a Livewire file upload in an AlpineJS component t
</form>
```
## JavaScript upload API
## JavaScript upload API
Integrating with 3rd-party file-uploading libraries often requires finer-tuned control than a simple `<input type="file">` tag.
Expand Down Expand Up @@ -413,11 +412,11 @@ The functions exist on the JavaScript component object, which can be accessed us
</script>
```
## Configuration
## Configuration
Because Livewire stores all file uploads temporarily before the developer has a chance to validate or store them, Livewire assumes some default handling of all file uploads.
### Global validation
### Global validation
By default, Livewire will validate ALL temporary file uploads with the following rules: `file|max:12288` (Must be a file less than 12MB).
Expand All @@ -430,7 +429,7 @@ If you wish to customize this, you can configure exactly what validate rules sho
],
```
### Global middleware
### Global middleware
The temporary file upload endpoint has throttling middleware by default. You can customize exactly what middleware this endpoint uses with the following configuration variable:
Expand All @@ -441,7 +440,7 @@ The temporary file upload endpoint has throttling middleware by default. You can
],
```
### Temporary upload directory
### Temporary upload directory
Temporary files are uploaded to the `livewire-tmp/` directory on the specified disk. You can customize this with the following configuration key:
Expand Down
11 changes: 11 additions & 0 deletions src/Attributes/Modelable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Livewire\Attributes;

use Livewire\Features\SupportWireModelingNestedComponents\Modelable as BaseModelable;

#[\Attribute]
class Modelable extends BaseModelable
{
//
}
11 changes: 11 additions & 0 deletions src/Attributes/Prop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Livewire\Attributes;

use Livewire\Features\SupportProps\Prop as BaseProp;

#[\Attribute]
class Prop extends BaseProp
{
//
}
11 changes: 11 additions & 0 deletions src/Attributes/ReactiveProp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Livewire\Attributes;

use Livewire\Features\SupportReactiveProps\ReactiveProp as BaseReactiveProp;

#[\Attribute]
class ReactiveProp extends BaseReactiveProp
{
//
}
12 changes: 12 additions & 0 deletions src/Attributes/Rule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Livewire\Attributes;

use Livewire\Features\SupportValidation\Rule as BaseRule;

#[\Attribute]
class Rule extends BaseRule
{
//
}

8 changes: 5 additions & 3 deletions src/Features/SupportLazyLoading/SupportLazyLoading.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ public function generatePlaceholderHtml($params)
{
$this->registerContainerComponent();

$snapshot = app('livewire')->snapshot(
$container = app('livewire')->new('__mountParamsContainer', ['forMount' => $params])
);
$container = app('livewire')->new('__mountParamsContainer');

$container->forMount = $params;

$snapshot = app('livewire')->snapshot($container);

$encoded = base64_encode(json_encode($snapshot));

Expand Down
18 changes: 18 additions & 0 deletions src/Features/SupportProps/Prop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Livewire\Features\SupportProps;

use Livewire\Features\SupportAttributes\Attribute as LivewireAttribute;

#[\Attribute]
class Prop extends LivewireAttribute
{
public function mount($params)
{
$property = $this->getName();

if (! array_key_exists($property, $params)) return;

$this->setValue($params[$property]);
}
}
32 changes: 32 additions & 0 deletions src/Features/SupportProps/UnitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Livewire\Features\SupportProps;

use Livewire\Livewire;
use Livewire\Component;
use ReflectionObject;

class UnitTest extends \Tests\TestCase
{
/** @test */
function can_pass_prop_to_child_component()
{
Livewire::test([new class extends Component {
public $foo = 'bar';

public function render() {
return '<livewire:child :oof="$foo" />';
}
}, 'child' => new class extends Component {
#[Prop]
public $oof;

public function render() {
return '<div>{{ $oof }}</div>';
}

}])
->assertSee('bar');
}
}

2 changes: 1 addition & 1 deletion src/Features/SupportReactiveProps/BrowserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function render() { return <<<'HTML'
}
},
'child' => new class extends Component {
#[Prop]
#[ReactiveProp]
public $count;

public function inc() { $this->count++; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Livewire\Features\SupportAttributes\Attribute as LivewireAttribute;

#[\Attribute]
class Prop extends LivewireAttribute
class ReactiveProp extends LivewireAttribute
{
public function mount($params)
{
Expand All @@ -16,7 +16,7 @@ public function mount($params)

$this->setValue($params[$property]);

store($this->component)->push('props', $property);
store($this->component)->push('reactiveProps', $property);
}

public function dehydrate($context)
Expand Down
8 changes: 4 additions & 4 deletions src/Features/SupportReactiveProps/SupportReactiveProps.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public static function provide()
});

on('dehydrate', function ($target, $context) {
$props = store($target)->get('props', []);
$propHashes = store($target)->get('propHashes', []);
$props = store($target)->get('reactiveProps', []);
$propHashes = store($target)->get('reactivePropHashes', []);

foreach ($propHashes as $key => $hash) {
if (crc32(json_encode($target->{$key})) !== $hash) {
Expand Down Expand Up @@ -52,8 +52,8 @@ public static function provide()
$propHashes[$key] = crc32(json_encode($target->{$key}));
}

store($target)->set('props', $propKeys);
store($target)->set('propHashes', $propHashes);
store($target)->set('reactiveProps', $propKeys);
store($target)->set('reactivePropHashes', $propHashes);

return $target;
});
Expand Down
2 changes: 1 addition & 1 deletion src/Features/SupportUnitTesting/Testable.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ static function create($name, $params = [], $queryParams = [])
if (is_array($otherComponents = $name)) {
$name = array_shift($otherComponents);

foreach ($name as $key => $value) {
foreach ($otherComponents as $key => $value) {
if (is_numeric($key)) app('livewire')->component($value);
else app('livewire')->component($key, $value);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Features/SupportValidation/HandlesValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ trait HandlesValidation

protected $rulesFromAttributes = [];

public function addRuleFromAttribute($property, $rule)
public function addRulesFromAttribute($rules)
{
$this->rulesFromAttributes[$property] = $rule;
$this->rulesFromAttributes = array_merge($this->rulesFromAttributes, $rules);
}

public function getErrorBag()
Expand Down
12 changes: 11 additions & 1 deletion src/Features/SupportValidation/Rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ function __construct(

function boot()
{
$this->component->addRuleFromAttribute($this->getName(), $this->rule);
$rules = [];

// Support setting rules by key-value for this and other properties:
// For example, #[Rule(['foo' => 'required', 'foo.*' => 'required'])]
if (is_array($this->rule) && count($this->rule) > 0 && ! is_numeric(array_keys($this->rule)[0])) {
$rules = $this->rule;
} else {
$rules[$this->getName()] = $this->rule;
}

$this->component->addRulesFromAttribute($rules);
}

function update($fullPath, $newValue)
Expand Down
28 changes: 27 additions & 1 deletion src/Features/SupportValidation/UnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class UnitTest extends \Tests\TestCase
{
/** @test */
public function validate_update_triggers_rule_attribute()
public function update_triggers_rule_attribute()
{
Livewire::test(new class extends TestComponent {
#[Rule('required')]
Expand All @@ -40,6 +40,32 @@ function save() { $this->validate(); }
]);
}

/** @test */
public function rule_attributes_can_contain_multiple_rules()
{
Livewire::test(new class extends TestComponent {
#[Rule(['foo' => 'required', 'bar' => 'required'])]
public $foo = '';

public $bar = '';

function clear() { $this->clearValidation(); }

function save() { $this->validate(); }
})
->set('bar', '')
->assertHasNoErrors()
->set('foo', '')
->assertHasErrors(['foo' => 'required'])
->call('clear')
->assertHasNoErrors()
->call('save')
->assertHasErrors([
'foo' => 'required',
'bar' => 'required',
]);
}

/** @test */
public function validate_with_rules_property()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ function precompiler($pattern, $callback)
app(ExtendBlade::class)->livewireOnlyPrecompiler($pattern, $callback);
}

function new($name, $params = [], $id = null)
function new($name, $id = null)
{
return app(ComponentRegistry::class)->new($name, $params, $id);
return app(ComponentRegistry::class)->new($name, $id);
}

function mount($name, $params = [], $key = null)
Expand Down
Loading

0 comments on commit 33bdf71

Please sign in to comment.