Skip to content
Merged
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
1 change: 1 addition & 0 deletions resources/dist/build/assets/addon-Dnt1-tBd.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion resources/dist/build/assets/addon-l0sNRNKZ.js

This file was deleted.

2 changes: 1 addition & 1 deletion resources/dist/build/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"resources/js/addon.js": {
"file": "assets/addon-l0sNRNKZ.js",
"file": "assets/addon-Dnt1-tBd.js",
"name": "addon",
"src": "resources/js/addon.js",
"isEntry": true
Expand Down
8 changes: 5 additions & 3 deletions resources/js/addon.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// No custom Control Panel components. MailerLite configuration lives on the
// native form configure page, injected via Form::appendConfigFields() in the
// addon service provider.
import MailerLiteFormFieldsFieldtype from './components/fieldtypes/MailerLiteFormFieldsFieldtype.vue';

Statamic.booting(() => {
Statamic.$components.register('mailer_lite_form_fields-fieldtype', MailerLiteFormFieldsFieldtype);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<Combobox
class="w-full"
clearable
searchable
:model-value="value"
:options="meta.options"
option-label="label"
option-value="value"
@update:model-value="update"
/>
</template>

<script setup>
import { Fieldtype } from '@statamic/cms';
import { Combobox } from '@statamic/cms/ui';

const emit = defineEmits(Fieldtype.emits);
const props = defineProps(Fieldtype.props);
const { expose, update } = Fieldtype.use(emit, props);
defineExpose(expose);
</script>
51 changes: 51 additions & 0 deletions src/Fieldtypes/MailerLiteFormFields.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Concept7\StatamicMailerLite\Fieldtypes;

use Statamic\Contracts\Forms\Form as FormContract;
use Statamic\Facades\Form;
use Statamic\Fields\Field;
use Statamic\Fields\Fieldtype;

class MailerLiteFormFields extends Fieldtype
{
protected $selectable = false;

/**
* The form is resolved from the current CP route because this fieldtype is
* registered through a wildcard Form::appendConfigFields() call, which has
* no form context of its own.
*
* @return array{options: array<int, array{label: string, value: string}>}
*/
public function preload(): array
{
return [
'options' => $this->formFieldOptions(),
];
}

/**
* @return array<int, array{label: string, value: string}>
*/
private function formFieldOptions(): array
{
$form = request()->route('form');

if (is_string($form)) {
$form = Form::find($form);
}

if (! $form instanceof FormContract) {
return [];
}

return $form->blueprint()->fields()->all()
->map(fn (Field $field): array => [
'label' => $field->display(),
'value' => $field->handle(),
])
->values()
->all();
}
}
30 changes: 11 additions & 19 deletions src/StatamicMailerLiteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
namespace Concept7\StatamicMailerLite;

use Concept7\StatamicMailerLite\Listeners\SubmissionCreatedListener;
use Statamic\Contracts\Forms\Form as FormContract;
use Statamic\Events\SubmissionCreated;
use Statamic\Facades\Form;
use Statamic\Fields\Field;
use Statamic\Providers\AddonServiceProvider;

class StatamicMailerLiteServiceProvider extends AddonServiceProvider
Expand All @@ -24,28 +22,24 @@ class StatamicMailerLiteServiceProvider extends AddonServiceProvider

public function bootAddon(): void
{
// bootAddon() already runs inside Statamic's booted phase, so the form
// repository is available and config fields can be appended directly.
// Wrapping this in Statamic::booted() would queue a callback that never
// runs — runBootedCallbacks() is already mid-drain at this point.
Form::all()->each(fn (FormContract $form) => Form::appendConfigFields(
$form->handle(),
// Registered with the '*' wildcard so booting never enumerates forms —
// with statamic/eloquent-driver that would query the database, which
// may be unreachable or unmigrated while the app still has to boot
// (package:discover, Larastan analysis, first deploy).
Form::appendConfigFields(
'*',
'MailerLite',
static::configFields($form),
));
static::configFields(),
);
}

/**
* Build the MailerLite section appended to a form's native configure page.
* Build the MailerLite section appended to every form's native configure page.
*
* @return array<string, array<string, mixed>>
*/
public static function configFields(FormContract $form): array
public static function configFields(): array
{
$formFieldOptions = $form->blueprint()->fields()->all()
->mapWithKeys(fn (Field $field): array => [$field->handle() => $field->display()])
->all();

return [
'mailerlite_enabled' => [
'type' => 'toggle',
Expand All @@ -70,10 +64,8 @@ public static function configFields(FormContract $form): array
[
'handle' => 'form_field',
'field' => [
'type' => 'select',
'type' => 'mailer_lite_form_fields',
'display' => __('Form field'),
'options' => $formFieldOptions,
'clearable' => false,
],
],
[
Expand Down
24 changes: 7 additions & 17 deletions tests/Feature/MailerLiteConfigFieldsTest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
<?php

use Concept7\StatamicMailerLite\StatamicMailerLiteServiceProvider;
use Statamic\Contracts\Forms\Form as FormContract;
use Statamic\Facades\Blueprint;
use Statamic\Facades\Form;

it('builds the MailerLite section with the three config fields', function () {
$fields = StatamicMailerLiteServiceProvider::configFields(Form::make('contact'));
$fields = StatamicMailerLiteServiceProvider::configFields();

expect($fields)->toHaveKeys(['mailerlite_enabled', 'mailerlite_group', 'mailerlite_field_mapping']);
expect($fields['mailerlite_enabled']['type'])->toBe('toggle');
Expand All @@ -17,7 +14,7 @@
});

it('uses a single-select MailerLite field inside the mapping grid', function () {
$fields = StatamicMailerLiteServiceProvider::configFields(Form::make('contact'));
$fields = StatamicMailerLiteServiceProvider::configFields();

$mailerLiteField = collect($fields['mailerlite_field_mapping']['fields'])
->firstWhere('handle', 'mailerlite_field')['field'];
Expand All @@ -26,18 +23,11 @@
expect($mailerLiteField['max_items'])->toBe(1);
});

it('offers the form fields as form_field options', function () {
$blueprint = Blueprint::makeFromFields([
'email' => ['type' => 'text'],
'name' => ['type' => 'text'],
])->setHandle('contact')->setNamespace('forms');
it('uses the dynamic form fields fieldtype inside the mapping grid', function () {
$fields = StatamicMailerLiteServiceProvider::configFields();

$form = Mockery::mock(FormContract::class);
$form->shouldReceive('handle')->andReturn('contact');
$form->shouldReceive('blueprint')->andReturn($blueprint);
$formField = collect($fields['mailerlite_field_mapping']['fields'])
->firstWhere('handle', 'form_field')['field'];

$options = collect(StatamicMailerLiteServiceProvider::configFields($form)['mailerlite_field_mapping']['fields'])
->firstWhere('handle', 'form_field')['field']['options'];

expect($options)->toHaveKeys(['email', 'name']);
expect($formField['type'])->toBe('mailer_lite_form_fields');
});
45 changes: 45 additions & 0 deletions tests/Feature/MailerLiteFormFieldsFieldtypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

use Concept7\StatamicMailerLite\Fieldtypes\MailerLiteFormFields;
use Illuminate\Routing\Route;
use Statamic\Contracts\Forms\Form as FormContract;
use Statamic\Facades\Blueprint;

it('preloads the form blueprint fields as options', function () {
$blueprint = Blueprint::makeFromFields([
'email' => ['type' => 'text'],
'name' => ['type' => 'text'],
])->setHandle('contact')->setNamespace('forms');

$form = Mockery::mock(FormContract::class);
$form->shouldReceive('blueprint')->andReturn($blueprint);

$route = new Route(['GET'], 'cp/forms/{form}/edit', []);
$route->parameters = ['form' => $form];

request()->setRouteResolver(fn (): Route => $route);

$options = (new MailerLiteFormFields)->preload()['options'];

expect(collect($options)->pluck('value')->all())->toBe([
'email',
'name',
]);
expect(collect($options)->pluck('label')->all())->toBe([
'Email',
'Name',
]);
});

it('preloads an empty option list when the route has no form', function () {
expect((new MailerLiteFormFields)->preload()['options'])->toBe([]);
});

it('preloads an empty option list when a form handle cannot be resolved', function () {
$route = new Route(['GET'], 'cp/forms/{form}/edit', []);
$route->parameters = ['form' => 'missing'];

request()->setRouteResolver(fn (): Route => $route);

expect((new MailerLiteFormFields)->preload()['options'])->toBe([]);
});
12 changes: 7 additions & 5 deletions tests/Feature/SectionRegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
use Concept7\StatamicMailerLite\StatamicMailerLiteServiceProvider;
use Statamic\Facades\Form;

it('appends the MailerLite section to forms during bootAddon', function () {
$form = Form::make('contact');

Form::partialMock()->shouldReceive('all')->andReturn(collect([$form]));

it('appends the MailerLite section to every form during bootAddon', function () {
app()->getProvider(StatamicMailerLiteServiceProvider::class)->bootAddon();

$sections = Form::extraConfigFor('contact');
Expand All @@ -16,3 +12,9 @@
expect(array_keys($sections['mailer_lite']['fields']))
->toBe(['mailerlite_enabled', 'mailerlite_group', 'mailerlite_field_mapping']);
});

it('boots without enumerating forms', function () {
Form::partialMock()->shouldReceive('all')->never();

app()->getProvider(StatamicMailerLiteServiceProvider::class)->bootAddon();
});