Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Facades/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @method static \Illuminate\Support\Collection all()
* @method static int count()
* @method static \Statamic\Contracts\Forms\Form make(string $handle = null)
* @method static void appendConfigFields(mixed $handles, string $display, array $fields)
* @method static void appendConfigFields(mixed $handles, string $display, array $fields, ?string $before = null, ?string $after = null)
* @method static array extraConfigFor(string $handle)
* @method static self redirect(string $form, \Closure $callback)
* @method static \Closure getSubmissionRedirect(Submission $submission)
Expand Down
15 changes: 11 additions & 4 deletions src/Forms/FormRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,18 @@ public function make($handle = null)
return $form;
}

public function appendConfigFields($handles, string $display, array $fields)
public function appendConfigFields($handles, string $display, array $fields, ?string $before = null, ?string $after = null)
{
if ($before && $after) {
throw new \InvalidArgumentException('Pass only before or after, not both.');
}

$this->configs[] = [
'display' => $display,
'handles' => Arr::wrap($handles),
'fields' => $fields,
'before' => $before,
'after' => $after,
];
}

Expand All @@ -103,14 +109,15 @@ public function extraConfigFor($handle)
return in_array('*', $config['handles']) || in_array($handle, $config['handles']);
})
->flatMap(function ($config) use ($reserved) {

return [
Str::snake($config['display']) => [
Str::snake($config['display']) => array_filter([
'display' => $config['display'],
'fields' => collect($config['fields'])
->filter(fn ($field, $index) => ! in_array($field['handle'] ?? $index, $reserved))
->all(),
],
'before' => $config['before'] ?? null,
'after' => $config['after'] ?? null,
], fn ($value) => ! is_null($value)),
];
})
->all();
Expand Down
45 changes: 43 additions & 2 deletions src/Http/Controllers/CP/Forms/FormsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Statamic\Http\Controllers\CP\Forms\Concerns\ProvidesFormAbilities;
use Statamic\Rules\Handle;
use Statamic\Statamic;
use Statamic\Support\Arr;
use Statamic\Support\Str;

use function Statamic\trans as __;
Expand Down Expand Up @@ -389,13 +390,23 @@ protected function editFormBlueprint($form)
$merged = false;
foreach ($fields as $sectionHandle => $section) {
if ($section['display'] == __($config['display'])) {
$fields[$sectionHandle]['fields'] += $config['fields'];
$fields[$sectionHandle]['fields'] = $this->insertRelative(
$section['fields'],
$config['fields'],
$config['before'] ?? null,
$config['after'] ?? null,
);
$merged = true;
}
}

if (! $merged) {
$fields[$handle] = $config;
$fields = $this->insertRelative(
$fields,
[$handle => Arr::except($config, ['before', 'after'])],
$config['before'] ?? null,
$config['after'] ?? null,
);
}
}

Expand All @@ -418,4 +429,34 @@ protected function editFormBlueprint($form)
])->all());

}

protected function insertRelative(array $existing, array $new, ?string $before = null, ?string $after = null): array
{
if (! $before && ! $after) {
return $existing + $new;
}

$result = [];
$inserted = false;

foreach ($existing as $handle => $item) {
if ($before === $handle) {
foreach ($new as $newHandle => $newItem) {
$result[$newHandle] = $newItem;
}
$inserted = true;
}

$result[$handle] = $item;

if ($after === $handle) {
foreach ($new as $newHandle => $newItem) {
$result[$newHandle] = $newItem;
}
$inserted = true;
}
}

return $inserted ? $result : $existing + $new;
}
}
91 changes: 91 additions & 0 deletions tests/Feature/Forms/EditFormTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,95 @@ public function fields_can_be_added()
'Second injected into additional section',
]);
}

#[Test]
public function fields_can_be_added_before_an_existing_field()
{
$this->setTestRoles(['test' => ['access cp', 'configure forms']]);
$user = User::make()->assignRole('test')->save();
$form = tap(Form::make('test'))->save();

Form::appendConfigFields('*', 'Fields', [
'recaptcha' => ['type' => 'text', 'display' => 'Injected before honeypot'],
], before: 'honeypot');

$this
->actingAs($user)
->get(cp_route('forms.edit', $form->handle()))
->assertSuccessful()
->assertSeeInOrder([
'Title',
'Injected before honeypot',
'Honeypot',
'Store Submissions',
]);
}

#[Test]
public function fields_can_be_added_after_an_existing_field()
{
$this->setTestRoles(['test' => ['access cp', 'configure forms']]);
$user = User::make()->assignRole('test')->save();
$form = tap(Form::make('test'))->save();

Form::appendConfigFields('*', 'Submissions', [
'webhook' => ['type' => 'text', 'display' => 'Injected after store'],
], after: 'store');

$this
->actingAs($user)
->get(cp_route('forms.edit', $form->handle()))
->assertSuccessful()
->assertSeeInOrder([
'Store Submissions',
'Injected after store',
'Enable Fake Submission Generator',
]);
}

#[Test]
public function sections_can_be_added_before_an_existing_section()
{
$this->setTestRoles(['test' => ['access cp', 'configure forms']]);
$user = User::make()->assignRole('test')->save();
$form = tap(Form::make('test'))->save();

Form::appendConfigFields('*', 'Automagic Forms', [
'automagic_form' => ['type' => 'toggle', 'display' => 'Enable Automagic Form'],
], before: 'submissions');

$this
->actingAs($user)
->get(cp_route('forms.edit', $form->handle()))
->assertSuccessful()
->assertSeeInOrder([
'Honeypot',
'Automagic Forms',
'Enable Automagic Form',
'Store Submissions',
]);
}

#[Test]
public function sections_can_be_added_after_an_existing_section()
{
$this->setTestRoles(['test' => ['access cp', 'configure forms']]);
$user = User::make()->assignRole('test')->save();
$form = tap(Form::make('test'))->save();

Form::appendConfigFields('*', 'Automagic Forms', [
'automagic_form' => ['type' => 'toggle', 'display' => 'Enable Automagic Form'],
], after: 'fields');

$this
->actingAs($user)
->get(cp_route('forms.edit', $form->handle()))
->assertSuccessful()
->assertSeeInOrder([
'Honeypot',
'Automagic Forms',
'Enable Automagic Form',
'Store Submissions',
]);
}
}
47 changes: 47 additions & 0 deletions tests/Forms/FormRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,51 @@ public function it_registers_config()
],
], $this->repo->extraConfigFor('another_form'));
}

#[Test]
public function it_registers_config_with_before_position()
{
$this->repo->appendConfigFields('*', 'Fields', [
'recaptcha' => ['type' => 'toggle'],
], before: 'honeypot');

$this->assertEquals([
'fields' => [
'display' => 'Fields',
'fields' => [
'recaptcha' => ['type' => 'toggle'],
],
'before' => 'honeypot',
],
], $this->repo->extraConfigFor('test_form'));
}

#[Test]
public function it_registers_config_with_after_position()
{
$this->repo->appendConfigFields('*', 'Fields', [
'recaptcha' => ['type' => 'toggle'],
], after: 'honeypot');

$this->assertEquals([
'fields' => [
'display' => 'Fields',
'fields' => [
'recaptcha' => ['type' => 'toggle'],
],
'after' => 'honeypot',
],
], $this->repo->extraConfigFor('test_form'));
}

#[Test]
public function it_throws_when_both_before_and_after_are_provided()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Pass only before or after, not both.');

$this->repo->appendConfigFields('*', 'Fields', [
'recaptcha' => ['type' => 'toggle'],
], before: 'honeypot', after: 'title');
}
}
Loading