Skip to content

Commit

Permalink
Fixed field handle updates bug
Browse files Browse the repository at this point in the history
  • Loading branch information
bencroker committed Aug 10, 2021
1 parent f3954c2 commit fba248d
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 23 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,9 @@
### Added
- Added the `isWebRequest` variable to campaign templates that evaluates to `true` if the campaign is being viewed via a web request using the browser URL ([#246](https://github.com/putyourlightson/craft-campaign/issues/246)).

### Fixed
- Fixed a bug in which field handle updates could cause an error on the segments index page ([#242](https://github.com/putyourlightson/craft-campaign/issues/242)).

## 1.20.2 - 2021-08-05
### Fixed
- Fixed a bug in which segments were not working with fields created in Craft 3.7.0 and above ([#241](https://github.com/putyourlightson/craft-campaign/issues/241)).
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -47,7 +47,7 @@
"developer": "PutYourLightsOn",
"developerUrl": "https://putyourlightson.com/",
"documentationUrl": "https://putyourlightson.com/plugins/campaign",
"schemaVersion": "1.18.0",
"schemaVersion": "1.20.3",
"hasCpSettings": true,
"hasCpSection": true,
"changelogUrl": "https://raw.githubusercontent.com/putyourlightson/craft-campaign/v1/CHANGELOG.md",
Expand Down
34 changes: 28 additions & 6 deletions src/Campaign.php
Expand Up @@ -9,6 +9,7 @@
use craft\base\Plugin;
use craft\elements\User;
use craft\errors\MissingComponentException;
use craft\events\FieldEvent;
use craft\events\PluginEvent;
use craft\events\RebuildConfigEvent;
use craft\events\RegisterComponentTypesEvent;
Expand Down Expand Up @@ -141,6 +142,7 @@ public function init()
$this->_registerElementTypes();
$this->_registerFieldTypes();
$this->_registerAfterInstallEvent();
$this->_registerFieldEvents();
$this->_registerProjectConfigListeners();
$this->_registerTemplateHooks();

Expand Down Expand Up @@ -341,12 +343,14 @@ protected function createSettingsModel(): SettingsModel

// Set defaults
$settings->apiKey = StringHelper::randomString(16);
$settings->fromNamesEmails = [[
Craft::parseEnv($mailSettings->fromName),
Craft::parseEnv($mailSettings->fromEmail),
'',
Craft::$app->getSites()->getPrimarySite()->id,
]];
$settings->fromNamesEmails = [
[
Craft::parseEnv($mailSettings->fromName),
Craft::parseEnv($mailSettings->fromEmail),
'',
Craft::$app->getSites()->getPrimarySite()->id,
]
];
$settings->transportType = Sendmail::class;

return $settings;
Expand Down Expand Up @@ -542,6 +546,24 @@ function(PluginEvent $event) {
);
}

/**
* Registers field events.
*/
private function _registerFieldEvents()
{
Event::on(Fields::class, Fields::EVENT_AFTER_SAVE_FIELD,
function(FieldEvent $event) {
$this->segments->updateField($event->field);
}
);

Event::on(Fields::class, Fields::EVENT_AFTER_DELETE_FIELD,
function(FieldEvent $event) {
$this->segments->deleteField($event->field);
}
);
}

/**
* Registers event listeners for project config changes.
*/
Expand Down
61 changes: 47 additions & 14 deletions src/helpers/SegmentHelper.php
Expand Up @@ -6,7 +6,7 @@
namespace putyourlightson\campaign\helpers;

use Craft;
use craft\base\Field;
use craft\base\FieldInterface;
use craft\fields\BaseOptionsField;
use craft\fields\Checkboxes;
use craft\fields\Date;
Expand All @@ -18,7 +18,6 @@
use craft\fields\PlainText;
use craft\fields\RadioButtons;
use craft\fields\Url;
use craft\helpers\ElementHelper;
use putyourlightson\campaign\Campaign;
use putyourlightson\campaign\events\RegisterSegmentAvailableFieldsEvent;
use putyourlightson\campaign\events\RegisterSegmentFieldOperatorsEvent;
Expand Down Expand Up @@ -124,7 +123,7 @@ public static function getAvailableFields(): array
$settings = Campaign::$plugin->getSettings();
$availableFields = [[
'type' => Email::class,
'handle' => 'email',
'column' => 'email',
'name' => $settings->emailFieldLabel,
'options' => null,
]];
Expand All @@ -135,21 +134,13 @@ public static function getAvailableFields(): array
if (!empty($fields)) {
$supportedFields = SegmentHelper::getFieldOperators();

/** @var Field $field */
foreach ($fields as $field) {
$fieldType = get_class($field);

if (!empty($supportedFields[$fieldType])) {
$fieldColumnPrefix = $field->columnPrefix ?? Craft::$app->getContent()->fieldColumnPrefix;
$fieldColumn = $fieldColumnPrefix.$field->handle;

if (version_compare(Craft::$app->version, '3.7.0', '>=')) {
$fieldColumn = ElementHelper::fieldColumnFromField($field);
}

$availableFields[] = [
'type' => $fieldType,
'handle' => $fieldColumn,
'column' => static::fieldColumnFromField($field),
'name' => $field->name,
'options' => ($field instanceof BaseOptionsField ? $field->options : null),
];
Expand All @@ -160,13 +151,13 @@ public static function getAvailableFields(): array
// Add date fields
$availableFields[] = [
'type' => Date::class,
'handle' => 'lastActivity',
'column' => 'lastActivity',
'name' => Craft::t('campaign', 'Last Activity'),
'options' => null,
];
$availableFields[] = [
'type' => Date::class,
'handle' => 'elements.dateCreated',
'column' => 'elements.dateCreated',
'name' => Craft::t('campaign', 'Date Created'),
'options' => null,
];
Expand All @@ -178,4 +169,46 @@ public static function getAvailableFields(): array

return $event->availableFields;
}

/**
* Returns the content column name for a given field.
* Replaces ElementHelper::fieldColumnFromField, added in Craft 3.7.0.
*
* @since 1.20.3
*/
public static function fieldColumnFromField(FieldInterface $field)
{
if ($field::hasContentColumn()) {
return static::fieldColumn($field->columnPrefix, $field->handle, $field->columnSuffix);
}

return null;
}

/**
* Returns the old content column name for a given field.
*
* @since 1.20.3
*/
public static function oldFieldColumnFromField(FieldInterface $field)
{
if ($field::hasContentColumn()) {
return static::fieldColumn($field->columnPrefix, $field->oldHandle, $field->columnSuffix);
}

return null;
}

/**
* Returns the content column name based on the given field attributes.
* Replaces ElementHelper::fieldColumn, added in Craft 3.7.0.
*
* @since 1.20.3
*/
public static function fieldColumn($columnPrefix, string $handle, string $columnSuffix = null): string
{
return ($columnPrefix ?? Craft::$app->getContent()->fieldColumnPrefix) .
$handle .
($columnSuffix ? "_$columnSuffix" : '');
}
}
70 changes: 70 additions & 0 deletions src/migrations/m210810_120000_update_segment_field_columns.php
@@ -0,0 +1,70 @@
<?php

namespace putyourlightson\campaign\migrations;

use Craft;
use craft\base\FieldInterface;
use craft\db\Migration;
use putyourlightson\campaign\elements\SegmentElement;
use putyourlightson\campaign\helpers\SegmentHelper;

class m210810_120000_update_segment_field_columns extends Migration
{
// Public Methods
// =========================================================================

/**
* @inheritdoc
*/
public function safeUp()
{
$fields = Craft::$app->fields->getAllFields();

foreach ($fields as $field) {
$this->_updateFieldColumn($field);
}

return true;
}

/**
* @inheritdoc
*/
public function safeDown(): bool
{
echo self::class." cannot be reverted.\n";

return false;
}

private function _updateFieldColumn(FieldInterface $field)
{
$newFieldColumn = SegmentHelper::fieldColumnFromField($field);
$oldFieldColumn = 'field_'.$field->handle;

if ($newFieldColumn && $newFieldColumn == $oldFieldColumn) {
return;
}

$updated = false;

$segments = SegmentElement::find()
->status(null)
->all();

foreach ($segments as $segment) {
foreach ($segment->conditions as &$andCondition) {
foreach ($andCondition as &$orCondition) {
if ($orCondition[1] == $oldFieldColumn) {
$orCondition[1] = $newFieldColumn;
$updated = true;
}
}
}

if ($updated) {
Craft::$app->elements->saveElement($segment);
}
}
}
}
56 changes: 56 additions & 0 deletions src/services/SegmentsService.php
Expand Up @@ -7,11 +7,13 @@

use Craft;
use craft\base\Component;
use craft\base\FieldInterface;
use craft\helpers\Db;
use craft\records\Element_SiteSettings;
use putyourlightson\campaign\elements\ContactElement;
use putyourlightson\campaign\elements\db\ContactElementQuery;
use putyourlightson\campaign\elements\SegmentElement;
use putyourlightson\campaign\helpers\SegmentHelper;
use Twig\Error\LoaderError;
use Twig\Error\SyntaxError;

Expand Down Expand Up @@ -170,6 +172,60 @@ public function getFilteredContactIds(SegmentElement $segment, array $contactIds
return $filteredContactIds;
}

public function updateField(FieldInterface $field)
{
$newFieldColumn = SegmentHelper::fieldColumnFromField($field);
$oldFieldColumn = SegmentHelper::oldFieldColumnFromField($field);

if ($newFieldColumn == $oldFieldColumn) {
return;
}

$updated = false;

$segments = SegmentElement::find()
->status(null)
->all();

foreach ($segments as $segment) {
foreach ($segment->conditions as &$andCondition) {
foreach ($andCondition as &$orCondition) {
if ($orCondition[1] == $oldFieldColumn) {
$orCondition[1] = $newFieldColumn;
$updated = true;
}
}
}

if ($updated) {
Craft::$app->elements->saveElement($segment);
}
}
}

public function deleteField(FieldInterface $field)
{
$segments = SegmentElement::find()
->status(null)
->all();

foreach ($segments as $segment) {
$fieldColumn = SegmentHelper::fieldColumnFromField($field);

foreach ($segment->conditions as &$andCondition) {
foreach ($andCondition as $key => $orCondition) {
if ($orCondition[1] == $fieldColumn) {
unset($andCondition[$key]);
}
}
}

if ($segment->isAttributeDirty('conditions')) {
Craft::$app->elements->saveElement($segment);
}
}
}

// Private Methods
// =========================================================================

Expand Down
4 changes: 2 additions & 2 deletions src/templates/segments/_includes/condition.html
Expand Up @@ -3,9 +3,9 @@
<div class="select">
<select name="conditions[{{ andIndex ?? '' }}][{{ orIndex ?? '' }}][1]" class="conditionField" {{ condition is not defined ? 'disabled' }}>
{% for field in availableFields %}
{% set value = field.handle %}
{% set value = field.column %}
<option data-field="field-{{ field.type|replace({'\\': '-'}) }}"
data-unique="{{ field.options ? field.handle }}"
data-unique="{{ field.options ? field.column }}"
value="{{ value }}"
{{ condition is defined and condition[1] == value ? 'selected' }}
>{{ field.name }}</option>
Expand Down

0 comments on commit fba248d

Please sign in to comment.