mirror of
https://github.com/archtechx/livewire-access.git
synced 2025-12-12 12:24:03 +00:00
implicit access
This commit is contained in:
parent
a5e58a14d8
commit
8df06ae2c3
9 changed files with 184 additions and 22 deletions
57
README.md
57
README.md
|
|
@ -1,8 +1,15 @@
|
||||||
# Explicit property/method access for Livewire
|
# Livewire Access
|
||||||
|
|
||||||
This package adds PHP 8.0 attribute support to Livewire. In specific, the attributes are used for flagging component properties and methods as *frontend-accessible*.
|
This package adds PHP 8.0 attribute support to Livewire. In specific, the attributes are used for flagging component properties and methods as *frontend-accessible*.
|
||||||
|
|
||||||
Components which implement the trait provided by this package will implicitly deny access to all properties and methods if they don't have the `#[FrontendAccess]` attribute, regardless of their visibility.
|
The package ships with two pairs of traits and attributes. One for *explicit* access, and one for *implicit* access.
|
||||||
|
|
||||||
|
- Components which implement the trait for **explicit** access will *deny* access to all properties and methods if they don't have the `#[FrontendAccess]` attribute.
|
||||||
|
- Components which implement the trait for **implicit** access will *allow* access unless the component has the `#[BlockFrontendAccess]` attribute.
|
||||||
|
|
||||||
|
This acts as a layer on top of Livewire's logic for distinguishing public properties, but it gives you the ability to manually make changes when you need more control than property/method visibility.
|
||||||
|
|
||||||
|
The trait for only allowing explicit access can also be useful to prevent accidentally making methods `public` when it's not needed, which has the potential to lead to security issues. This can be especially useful on teams with junior engineers who don't yet have a full understanding of Livewire's internals, but can be very productive with it.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -12,6 +19,12 @@ composer require leanadmin/livewire-access
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
This package doesn't make any changes to your existing code. Components which don't implement either one of its traits will not be affected.
|
||||||
|
|
||||||
|
### Explicit access
|
||||||
|
|
||||||
|
To enable the explicit access mode, i.e. only enable access to properties/methods that explicitly allow it, use the `WithExplicitAccess` trait.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Lean\LivewireAccess\WithExplicitAccess;
|
use Lean\LivewireAccess\WithExplicitAccess;
|
||||||
|
|
@ -34,16 +47,50 @@ class MyComponent extends Component
|
||||||
}
|
}
|
||||||
|
|
||||||
#[FrontendAccess]
|
#[FrontendAccess]
|
||||||
public function secretMethod()
|
public function publicMethod()
|
||||||
{
|
{
|
||||||
// This method allows frontend access
|
// This method allows frontend access
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The properties still need to be `public` to be accessible.
|
### Implicit access
|
||||||
|
|
||||||
The thrown exceptions are identical to those that Livewire would throw if the properties/methods were not public.
|
To enable the implicit access mode, i.e. keep using the same mode , use the `WithExplicitAccess` trait.
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Livewire\Component;
|
||||||
|
use Lean\LivewireAccess\WithImplicitAccess;
|
||||||
|
use Lean\LivewireAccess\FrontendAccess;
|
||||||
|
|
||||||
|
class MyComponent extends Component
|
||||||
|
{
|
||||||
|
// Use the trait on your component to enable this functionality
|
||||||
|
use WithImplicitAccess;
|
||||||
|
|
||||||
|
// This property allows frontend access
|
||||||
|
public string $accessible;
|
||||||
|
|
||||||
|
#[BlockFrontendAccess]
|
||||||
|
public string $inaccessible; // This property blocks frontend access
|
||||||
|
|
||||||
|
public function publicMethod()
|
||||||
|
{
|
||||||
|
// This method allows frontend access
|
||||||
|
}
|
||||||
|
|
||||||
|
#[BlockFrontendAccess]
|
||||||
|
public function secretMethod()
|
||||||
|
{
|
||||||
|
// This method blocks frontend access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
- The properties still need to be `public` to be accessible.
|
||||||
|
- The thrown exceptions are identical to those that Livewire would throw if the properties/methods were not public.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "leanadmin/livewire-access",
|
"name": "leanadmin/livewire-access",
|
||||||
"description": "",
|
"description": "Control frontend access to properties/methods in Livewire using PHP 8 attributes.",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
|
||||||
12
src/BlockFrontendAccess.php
Normal file
12
src/BlockFrontendAccess.php
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Lean\LivewireAccess;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)]
|
||||||
|
class BlockFrontendAccess
|
||||||
|
{
|
||||||
|
}
|
||||||
23
src/WithImplicitAccess.php
Normal file
23
src/WithImplicitAccess.php
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Lean\LivewireAccess;
|
||||||
|
|
||||||
|
use ReflectionMethod;
|
||||||
|
use ReflectionProperty;
|
||||||
|
|
||||||
|
trait WithImplicitAccess
|
||||||
|
{
|
||||||
|
protected function methodIsPublicAndNotDefinedOnBaseClass($methodName)
|
||||||
|
{
|
||||||
|
return parent::methodIsPublicAndNotDefinedOnBaseClass($methodName)
|
||||||
|
&& count((new ReflectionMethod($this, $methodName))->getAttributes(BlockFrontendAccess::class)) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function propertyIsPublicAndNotDefinedOnBaseClass($propertyName)
|
||||||
|
{
|
||||||
|
return parent::propertyIsPublicAndNotDefinedOnBaseClass($propertyName)
|
||||||
|
&& count((new ReflectionProperty($this, $propertyName))->getAttributes(BlockFrontendAccess::class)) === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,49 +5,40 @@ namespace Lean\LivewireAccess\Tests;
|
||||||
use Livewire\Exceptions\NonPublicComponentMethodCall;
|
use Livewire\Exceptions\NonPublicComponentMethodCall;
|
||||||
use Livewire\Exceptions\PublicPropertyNotFoundException;
|
use Livewire\Exceptions\PublicPropertyNotFoundException;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
use Livewire\LivewireServiceProvider;
|
|
||||||
use Orchestra\Testbench\TestCase as TestbenchTestCase;
|
|
||||||
|
|
||||||
class LivewireAccessTest extends TestbenchTestCase
|
class ExplicitAccessTest extends TestCase
|
||||||
{
|
{
|
||||||
protected function getPackageProviders($app)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
LivewireServiceProvider::class,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function public_properties_are_not_accessible_by_default()
|
public function public_properties_are_not_accessible_by_default()
|
||||||
{
|
{
|
||||||
$this->expectException(PublicPropertyNotFoundException::class);
|
$this->expectException(PublicPropertyNotFoundException::class);
|
||||||
|
|
||||||
Livewire::test(TestComponent::class)
|
Livewire::test(ExplicitComponent::class)
|
||||||
->call('$set', 'foo', 'xxx');
|
->call('$set', 'foo', 'xxx');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function public_properties_can_be_explicitly_accessible()
|
public function public_properties_can_be_explicitly_accessible()
|
||||||
{
|
{
|
||||||
Livewire::test(TestComponent::class)
|
Livewire::test(ExplicitComponent::class)
|
||||||
->call('$set', 'bar', 'xxx');
|
->call('$set', 'bar', 'xxx');
|
||||||
|
|
||||||
// No exception
|
// No exception
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function public_methods_are_not_acccessible_by_default()
|
public function public_methods_are_not_accessible_by_default()
|
||||||
{
|
{
|
||||||
$this->expectException(NonPublicComponentMethodCall::class);
|
$this->expectException(NonPublicComponentMethodCall::class);
|
||||||
|
|
||||||
Livewire::test(TestComponent::class)
|
Livewire::test(ExplicitComponent::class)
|
||||||
->call('abc');
|
->call('abc');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function public_methods_can_be_explicitly_accessible()
|
public function public_methods_can_be_explicitly_accessible()
|
||||||
{
|
{
|
||||||
Livewire::test(TestComponent::class)
|
Livewire::test(ExplicitComponent::class)
|
||||||
->call('def');
|
->call('def');
|
||||||
|
|
||||||
// No exception
|
// No exception
|
||||||
|
|
@ -6,7 +6,7 @@ use Lean\LivewireAccess\WithExplicitAccess;
|
||||||
use Lean\LivewireAccess\FrontendAccess;
|
use Lean\LivewireAccess\FrontendAccess;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class TestComponent extends Component
|
class ExplicitComponent extends Component
|
||||||
{
|
{
|
||||||
use WithExplicitAccess;
|
use WithExplicitAccess;
|
||||||
|
|
||||||
46
tests/ImplicitAccessTest.php
Normal file
46
tests/ImplicitAccessTest.php
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lean\LivewireAccess\Tests;
|
||||||
|
|
||||||
|
use Livewire\Exceptions\NonPublicComponentMethodCall;
|
||||||
|
use Livewire\Exceptions\PublicPropertyNotFoundException;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
class ImplicitAccessTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @test */
|
||||||
|
public function public_properties_are_accessible_by_default()
|
||||||
|
{
|
||||||
|
// No exception
|
||||||
|
|
||||||
|
Livewire::test(ImplicitComponent::class)
|
||||||
|
->call('$set', 'foo', 'xxx');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function public_properties_can_be_explicitly_blocked()
|
||||||
|
{
|
||||||
|
$this->expectException(PublicPropertyNotFoundException::class);
|
||||||
|
|
||||||
|
Livewire::test(ImplicitComponent::class)
|
||||||
|
->call('$set', 'bar', 'xxx');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function public_methods_are_accessible_by_default()
|
||||||
|
{
|
||||||
|
Livewire::test(ImplicitComponent::class)
|
||||||
|
->call('abc');
|
||||||
|
|
||||||
|
// No exception
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function public_methods_can_be_explicitly_blocked()
|
||||||
|
{
|
||||||
|
$this->expectException(NonPublicComponentMethodCall::class);
|
||||||
|
|
||||||
|
Livewire::test(ImplicitComponent::class)
|
||||||
|
->call('def');
|
||||||
|
}
|
||||||
|
}
|
||||||
27
tests/ImplicitComponent.php
Normal file
27
tests/ImplicitComponent.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lean\LivewireAccess\Tests;
|
||||||
|
|
||||||
|
use Lean\LivewireAccess\BlockFrontendAccess;
|
||||||
|
use Lean\LivewireAccess\WithImplicitAccess;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class ImplicitComponent extends Component
|
||||||
|
{
|
||||||
|
use WithImplicitAccess;
|
||||||
|
|
||||||
|
public string $foo = 'foo';
|
||||||
|
|
||||||
|
#[BlockFrontendAccess]
|
||||||
|
public string $bar = 'bar';
|
||||||
|
|
||||||
|
public function abc() {}
|
||||||
|
|
||||||
|
#[BlockFrontendAccess]
|
||||||
|
public function def() {}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
16
tests/TestCase.php
Normal file
16
tests/TestCase.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lean\LivewireAccess\Tests;
|
||||||
|
|
||||||
|
use Livewire\LivewireServiceProvider;
|
||||||
|
use Orchestra\Testbench\TestCase as TestbenchTestCase;
|
||||||
|
|
||||||
|
class TestCase extends TestbenchTestCase
|
||||||
|
{
|
||||||
|
protected function getPackageProviders($app)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
LivewireServiceProvider::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue