diff --git a/tests/Factories/DataBlueprintFactory.php b/tests/Factories/DataBlueprintFactory.php index 3b582245e..9b90207f8 100644 --- a/tests/Factories/DataBlueprintFactory.php +++ b/tests/Factories/DataBlueprintFactory.php @@ -14,6 +14,9 @@ class DataBlueprintFactory /** @var \Spatie\LaravelData\Tests\Factories\DataPropertyBlueprintFactory[] */ private array $properties = []; + /** @var \Spatie\LaravelData\Tests\Factories\DataMagicMethodFactory[] */ + private array $methods = []; + public function __construct(?string $name = null) { $this->name = $name ?? 'Data' . uniqid(); @@ -33,6 +36,15 @@ public function withProperty(DataPropertyBlueprintFactory ...$properties): self return $clone; } + public function withMethod(DataMagicMethodFactory ...$methods): self + { + $clone = clone $this; + + $clone->methods = $methods; + + return $clone; + } + public function create(): string { eval($this->toString()); @@ -46,6 +58,14 @@ public function toString(): string $class->setExtends(Data::class); + $methods = array_map( + fn(DataMagicMethodFactory $factory) => $factory->create(), + $this->methods + ); + + $class->setMethods($methods); + + /** @var \Illuminate\Support\Collection $properties */ /** @var \Illuminate\Support\Collection $promotedProperties */ [$promotedProperties, $properties] = collect($this->properties) diff --git a/tests/Factories/DataMagicMethodFactory.php b/tests/Factories/DataMagicMethodFactory.php new file mode 100644 index 000000000..3c04f6570 --- /dev/null +++ b/tests/Factories/DataMagicMethodFactory.php @@ -0,0 +1,59 @@ +inputType = $inputType; + $clone->inputName = $inputName; + + return $clone; + } + + public function withBody(string $body): self + { + $clone = clone $this; + + $clone->body = $body; + + return $clone; + } + + public function create(): Method + { + $method = new Method($this->name); + + $method->addBody($this->body); + $method->setStatic(true); + $method->setReturnType('static'); + $method->setParameters([(new Parameter($this->inputName))->setType($this->inputType)]); + + return $method; + } +} diff --git a/tests/RequestDataTest.php b/tests/RequestDataTest.php index ba27a7187..5db20588f 100644 --- a/tests/RequestDataTest.php +++ b/tests/RequestDataTest.php @@ -3,11 +3,14 @@ namespace Spatie\LaravelData\Tests; use Illuminate\Auth\AuthenticationException; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use Illuminate\Testing\TestResponse; use Illuminate\Validation\ValidationException; use Illuminate\Validation\Validator; +use Spatie\LaravelData\Data; use Spatie\LaravelData\Tests\Factories\DataBlueprintFactory; +use Spatie\LaravelData\Tests\Factories\DataMagicMethodFactory; use Spatie\LaravelData\Tests\Factories\DataPropertyBlueprintFactory; use Spatie\LaravelData\Tests\Fakes\RequestData; use Spatie\LaravelData\Tests\Fakes\SimpleData; @@ -84,7 +87,7 @@ public function it_can_overwrite_validation_attributes() /** @test */ public function it_can_change_the_validator() { - RequestData::$validatorClosure = fn (Validator $validator) => $validator->setRules([]); + RequestData::$validatorClosure = fn(Validator $validator) => $validator->setRules([]); $this->invalidRequest() ->assertOk() @@ -174,6 +177,31 @@ public function it_can_check_for_authorisation() $this->validRequest()->assertStatus(401); } + /** @test */ + public function it_can_manually_override_how_the_data_object_will_be_constructed() + { + DataBlueprintFactory::new('OverrideableDataFromRequest') + ->withProperty(DataPropertyBlueprintFactory::new('name')->withType('string')) + ->withMethod( + DataMagicMethodFactory::new('fromRequest') + ->withInputType(Request::class, 'request') + ->withBody('return new self("{$request->input(\'first_name\')} {$request->input(\'last_name\')}");') + ) + ->create(); + + Route::post('/other-route', function (\OverrideableDataFromRequest $data) { + return ['name' => $data->name]; + }); + + $this->postJson('/other-route', [ + 'name' => 'ignore', // TODO, how can we remove this rule? + 'first_name' => 'Rick', + 'last_name' => 'Astley', + ]) + ->assertOk() + ->assertJson(['name' => 'Rick Astley']); + } + private function validRequest(): TestResponse { return $this->postJson('/example-route', [