Skip to content

Commit b1d2ef9

Browse files
committed
[Forms] add custom status field to form and allow for filtering in backend
1 parent b4c4f67 commit b1d2ef9

File tree

7 files changed

+246
-17
lines changed

7 files changed

+246
-17
lines changed

src/elements/Form.php

+55-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
namespace verbb\formie\elements;
34

45
use verbb\formie\Formie;
@@ -21,15 +22,12 @@
2122
use verbb\formie\models\FormTemplate;
2223
use verbb\formie\models\HtmlTag;
2324
use verbb\formie\models\Notification;
24-
use verbb\formie\models\Settings;
2525
use verbb\formie\models\Status;
2626
use verbb\formie\records\Form as FormRecord;
2727
use verbb\formie\services\Statuses;
2828

2929
use Craft;
3030
use craft\base\Element;
31-
use craft\db\Query;
32-
use craft\db\Table;
3331
use craft\elements\Entry;
3432
use craft\elements\User;
3533
use craft\elements\actions\Delete;
@@ -55,13 +53,20 @@
5553

5654
use Twig\Error\SyntaxError;
5755
use Twig\Error\LoaderError;
56+
use verbb\formie\elements\actions\SetFormStatus;
5857

5958
class Form extends Element
6059
{
6160
// Constants
6261
// =========================================================================
6362

6463
public const EVENT_MODIFY_HTML_TAG = 'modifyHtmlTag';
64+
public const STATUS_ACTIVE = 'active';
65+
public const STATUS_INACTIVE = 'inactive';
66+
public const STATUSES = [
67+
self::STATUS_ACTIVE,
68+
self::STATUS_INACTIVE,
69+
];
6570

6671

6772
// Static Methods
@@ -99,6 +104,19 @@ public static function hasContent(): bool
99104
return true;
100105
}
101106

107+
public static function hasStatuses(): bool
108+
{
109+
return true;
110+
}
111+
112+
public static function statuses(): array
113+
{
114+
return [
115+
self::STATUS_ACTIVE => Craft::t('app', 'Active'),
116+
self::STATUS_INACTIVE => Craft::t('app', 'Inactive'),
117+
];
118+
}
119+
102120
/**
103121
* @inheritDoc
104122
*/
@@ -155,7 +173,7 @@ public static function defineSources(string $context = null): array
155173

156174
return $sources;
157175
}
158-
176+
159177
/**
160178
* @inheritDoc
161179
*/
@@ -196,7 +214,6 @@ protected static function defineFieldLayouts(string $source): array
196214
protected static function defineActions(string $source = null): array
197215
{
198216
$actions = [];
199-
200217
$canDeleteForms = Craft::$app->getUser()->checkPermission('formie-deleteForms');
201218

202219
$actions[] = DuplicateForm::class;
@@ -215,6 +232,10 @@ protected static function defineActions(string $source = null): array
215232
'partialSuccessMessage' => Craft::t('formie', 'Some forms restored.'),
216233
'failMessage' => Craft::t('formie', 'Forms not restored.'),
217234
];
235+
$actions[] = [
236+
'type' => SetFormStatus::class,
237+
'statuses' => self::STATUSES,
238+
];
218239

219240
return $actions;
220241
}
@@ -228,6 +249,7 @@ protected static function defineTableAttributes(): array
228249
'title' => ['label' => Craft::t('app', 'Title')],
229250
'id' => ['label' => Craft::t('app', 'ID')],
230251
'handle' => ['label' => Craft::t('app', 'Handle')],
252+
'formStatus' => ['label' => Craft::t('formie', 'Status')],
231253
'template' => ['label' => Craft::t('app', 'Template')],
232254
'usageCount' => ['label' => Craft::t('formie', 'Usage Count')],
233255
'dateCreated' => ['label' => Craft::t('app', 'Date Created')],
@@ -288,6 +310,7 @@ protected static function defineSortOptions(): array
288310
// Properties
289311
// =========================================================================
290312

313+
private ?string $formStatus = self::STATUS_ACTIVE;
291314
public ?string $handle = null;
292315
public ?string $oldHandle = null;
293316
public ?string $fieldContentTable = null;
@@ -385,7 +408,7 @@ public function behaviors(): array
385408

386409
return $behaviors;
387410
}
388-
411+
389412
/**
390413
* @inheritdoc
391414
*/
@@ -555,6 +578,23 @@ public function getDefaultStatus(): ?Status
555578
return $this->_defaultStatus;
556579
}
557580

581+
public function setFormStatus(string $status = null): void
582+
{
583+
if ($status !== null) {
584+
$this->formStatus = $status;
585+
}
586+
}
587+
588+
public function getFormStatus(): string
589+
{
590+
return $this->formStatus ?? self::STATUS_ACTIVE;
591+
}
592+
593+
public function getStatus(): string
594+
{
595+
return $this->getFormStatus();
596+
}
597+
558598
/**
559599
* Sets the default status.
560600
*
@@ -1296,7 +1336,7 @@ public function getPageFieldErrors($submission): array
12961336
public function renderTemplate(array|string $components, array $variables = []): string
12971337
{
12981338
$view = Craft::$app->getView();
1299-
1339+
13001340
// Normalise the components to allow for a single component
13011341
if (!is_array($components)) {
13021342
$components = [$components];
@@ -1579,7 +1619,7 @@ public function defineHtmlTag(string $key, array $context = []): ?HtmlTag
15791619
$page = $context['page'] ?? null;
15801620
$inputAttributes = $page->settings->getInputAttributes() ?? [];
15811621
$saveButtonStyle = $page->settings->saveButtonStyle ?? 'link';
1582-
1622+
15831623
return new HtmlTag('button', [
15841624
'class' => [
15851625
'fui-btn fui-save',
@@ -1899,7 +1939,7 @@ public function setSettings($settings, $updateSnapshot = true): void
18991939
public function setFieldSettings($handle, $settings, $updateSnapshot = true): void
19001940
{
19011941
$field = null;
1902-
1942+
19031943
// Check for nested fields so we can use `group.dropdown` or `dropdown`.
19041944
$handles = explode('.', $handle);
19051945

@@ -1930,7 +1970,7 @@ public function setIntegrationSettings(string $handle, array $settings, $updateS
19301970
{
19311971
// Get the integration settings so we only override what we want
19321972
$integrationSettings = $this->settings->integrations[$handle] ?? [];
1933-
1973+
19341974
// Update the integration settings
19351975
$this->settings->integrations[$handle] = array_merge($integrationSettings, $settings);
19361976

@@ -2018,7 +2058,7 @@ public function isBeforeSchedule(): bool
20182058
if ($this->settings->scheduleForm && $this->settings->scheduleFormStart) {
20192059
return !DateTimeHelper::isInThePast($this->settings->scheduleFormStart);
20202060
}
2021-
2061+
20222062
return false;
20232063
}
20242064

@@ -2027,7 +2067,7 @@ public function isAfterSchedule(): bool
20272067
if ($this->settings->scheduleForm && $this->settings->scheduleFormEnd) {
20282068
return DateTimeHelper::isInThePast($this->settings->scheduleFormEnd);
20292069
}
2030-
2070+
20312071
return false;
20322072
}
20332073

@@ -2065,7 +2105,7 @@ public function isWithinSubmissionsLimit(): bool
20652105
return false;
20662106
}
20672107
}
2068-
2108+
20692109
return true;
20702110
}
20712111

@@ -2149,6 +2189,7 @@ public function afterSave(bool $isNew): void
21492189

21502190
$record->handle = $this->handle;
21512191
$record->fieldContentTable = $this->fieldContentTable;
2192+
$record->formStatus = $this->formStatus;
21522193
$record->settings = $this->settings;
21532194
$record->templateId = $this->templateId;
21542195
$record->submitActionEntryId = $this->submitActionEntryId;
@@ -2286,7 +2327,7 @@ protected function defineRules(): array
22862327
];
22872328

22882329
$rules[] = [
2289-
'handle', function($attribute, $params, Validator $validator): void {
2330+
'handle', function ($attribute, $params, Validator $validator): void {
22902331
$query = static::find()->handle($this->$attribute);
22912332
if ($this->id) {
22922333
$query = $query->id("not {$this->id}");
+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace verbb\formie\elements\actions;
4+
5+
use verbb\formie\Formie;
6+
7+
use Craft;
8+
use craft\elements\actions\SetStatus;
9+
use craft\elements\db\ElementQueryInterface;
10+
use craft\helpers\Json;
11+
use verbb\formie\elements\Form;
12+
13+
class SetFormStatus extends SetStatus
14+
{
15+
// Properties
16+
// =========================================================================
17+
18+
public ?string $formStatus = null;
19+
public array $statuses = [];
20+
21+
22+
// Public Methods
23+
// =========================================================================
24+
25+
public function getTriggerLabel(): string
26+
{
27+
return Craft::t('app', 'Set Status');
28+
}
29+
30+
public function getTriggerHtml(): ?string
31+
{
32+
return Craft::$app->getView()->renderTemplate('formie/_components/actions/form-set-status/trigger', [
33+
'statuses' => $this->statuses,
34+
]);
35+
}
36+
37+
/**
38+
* @inheritdoc
39+
*/
40+
public function performAction(ElementQueryInterface $query): bool
41+
{
42+
$elementsService = Craft::$app->getElements();
43+
44+
$elements = $query->all();
45+
$failCount = 0;
46+
47+
/** @var Form $element */
48+
foreach ($elements as $element) {
49+
if ($element) {
50+
$element->setFormStatus($this->formStatus);
51+
52+
if ($elementsService->saveElement($element) === false) {
53+
Formie::error('Unable to set status: {error}', ['error' => Json::encode($element->getErrors())]);
54+
55+
// Validation error
56+
$failCount++;
57+
}
58+
}
59+
}
60+
61+
// Did all of them fail?
62+
if ($failCount === count($elements)) {
63+
if (count($elements) === 1) {
64+
$this->setMessage(Craft::t('app', 'Could not update status due to a validation error.'));
65+
} else {
66+
$this->setMessage(Craft::t('app', 'Could not update statuses due to validation errors.'));
67+
}
68+
69+
return false;
70+
}
71+
72+
if ($failCount !== 0) {
73+
$this->setMessage(Craft::t('app', 'Status updated, with some failures due to validation errors.'));
74+
} else if (count($elements) === 1) {
75+
$this->setMessage(Craft::t('app', 'Status updated.'));
76+
} else {
77+
$this->setMessage(Craft::t('app', 'Statuses updated.'));
78+
}
79+
80+
return true;
81+
}
82+
83+
84+
// Protected Methods
85+
// =========================================================================
86+
87+
protected function defineRules(): array
88+
{
89+
// Don't include the parent rules from `SetStatus`
90+
$rules = [];
91+
92+
$rules[] = [['formStatus'], 'required'];
93+
$rules[] = [['formStatus'], 'in', 'range' => $this->statuses];
94+
95+
return $rules;
96+
}
97+
}

src/elements/db/FormQuery.php

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?php
2+
23
namespace verbb\formie\elements\db;
34

45
use verbb\formie\models\FormTemplate;
5-
6+
use verbb\formie\elements\Form;
67
use craft\db\Query;
78
use craft\elements\db\ElementQuery;
89
use craft\helpers\Db;
@@ -14,6 +15,7 @@ class FormQuery extends ElementQuery
1415

1516
public mixed $handle = null;
1617
public mixed $templateId = null;
18+
public mixed $formStatus = null;
1719

1820
protected array $defaultOrderBy = ['elements.dateCreated' => SORT_DESC];
1921

@@ -50,6 +52,23 @@ public function templateId($value): static
5052
return $this;
5153
}
5254

55+
public function status(array|string|null $value): static
56+
{
57+
$this->formStatus = $value;
58+
59+
return $this;
60+
}
61+
62+
63+
protected function statusCondition(string $status): mixed
64+
{
65+
if (in_array($status, FORM::STATUSES, true)) {
66+
return ['formie_forms.formStatus' => $status];
67+
}
68+
69+
return [];
70+
}
71+
5372

5473
// Protected Methods
5574
// =========================================================================
@@ -60,6 +79,7 @@ protected function beforePrepare(): bool
6079

6180
$this->query->select([
6281
'formie_forms.id',
82+
'formie_forms.formStatus',
6383
'formie_forms.handle',
6484
'formie_forms.fieldContentTable',
6585
'formie_forms.settings',
@@ -83,6 +103,10 @@ protected function beforePrepare(): bool
83103
$this->subQuery->andWhere(Db::parseParam('formie_forms.templateId', $this->templateId));
84104
}
85105

106+
if ($this->formStatus) {
107+
$this->subQuery->andWhere(Db::parseParam('formie_forms.formStatus', $this->formStatus));
108+
}
109+
86110
return parent::beforePrepare();
87111
}
88112
}

0 commit comments

Comments
 (0)