Skip to content

Commit

Permalink
fix drag and drop, better use of drafts
Browse files Browse the repository at this point in the history
  • Loading branch information
markhuot committed Oct 9, 2023
1 parent 41b9140 commit 9604a2c
Show file tree
Hide file tree
Showing 16 changed files with 462 additions and 80 deletions.
5 changes: 5 additions & 0 deletions src/Keystone.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@

use Craft;
use craft\base\Plugin;
use craft\services\Elements;
use craft\services\Fields;
use craft\web\Application as WebApplication;
use craft\web\Response;
use craft\web\UrlManager;
use markhuot\keystone\listeners\AddBodyParamObjectBehavior;
use markhuot\keystone\actions\GetComponentType;
use markhuot\keystone\listeners\AfterPropagateElement;
use markhuot\keystone\listeners\OverrideDraftResponseWithFieldHtml;
use markhuot\keystone\listeners\RegisterCpUrlRules;
use markhuot\keystone\listeners\RegisterDefaultComponentTypes;
use markhuot\keystone\listeners\RegisterKeystoneFieldType;
Expand All @@ -30,6 +34,7 @@ public function init(): void
[Fields::class, Fields::EVENT_REGISTER_FIELD_TYPES, RegisterKeystoneFieldType::class],
[UrlManager::class, UrlManager::EVENT_REGISTER_CP_URL_RULES, RegisterCpUrlRules::class],
[GetComponentType::class, GetComponentType::EVENT_REGISTER_COMPONENT_TYPES, RegisterDefaultComponentTypes::class],
[Response::class, Response::EVENT_AFTER_PREPARE, OverrideDraftResponseWithFieldHtml::class],
);
}
}
34 changes: 19 additions & 15 deletions src/actions/AddComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use craft\helpers\Db;
use craft\helpers\StringHelper;
use markhuot\keystone\db\Table;
use markhuot\keystone\models\Component;
use markhuot\keystone\models\ComponentData;

class AddComponent
{
Expand All @@ -15,21 +17,23 @@ public function handle(
string $path,
string $slot,
string $type
) {
$level = count(explode('/', $path));
$date = Db::prepareDateForDb(new \DateTime);
): Component {
$componentData = new ComponentData;
$componentData->type = $type;

Check failure on line 22 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\ComponentData::$type.
$componentData->save();

\Craft::$app->getDb()->createCommand()->insert(Table::COMPONENTS, [
'elementId' => $elementId,
'fieldId' => $fieldId,
'type' => $type,
'sortOrder' => $sortOrder,
'path' => $path,
'level' => $level,
'slot' => $slot,
'dateCreated' => $date,
'dateUpdated' => $date,
'uid' => StringHelper::UUID(),
]);
$component = new Component;
$component->elementId = $elementId;

Check failure on line 26 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$elementId.
$component->fieldId = $fieldId;

Check failure on line 27 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$fieldId.
$component->dataId = $componentData->id;

Check failure on line 28 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$dataId.

Check failure on line 28 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\ComponentData::$id.
$component->path = $path;

Check failure on line 29 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$path.
$component->slot = $slot;

Check failure on line 30 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$slot.
$component->type = $type;

Check failure on line 31 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$type.
$component->sortOrder = $sortOrder;

Check failure on line 32 in src/actions/AddComponent.php

View workflow job for this annotation

GitHub Actions / Run PHPStan

Access to an undefined property markhuot\keystone\models\Component::$sortOrder.
$component->save();

$component->refresh();

return $component;
}
}
76 changes: 76 additions & 0 deletions src/actions/DuplicateComponentTree.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace markhuot\keystone\actions;

use Craft;
use craft\base\ElementInterface;
use craft\helpers\DateTimeHelper;
use craft\helpers\StringHelper;
use markhuot\keystone\db\Table;
use markhuot\keystone\fields\Keystone;
use markhuot\keystone\models\Component;

class DuplicateComponentTree
{
static array $mapping = [];

public function handle(ElementInterface $source, ElementInterface $destination, Keystone $field)
{
$query = Component::find()->where([
'elementId' => $source->id,
'fieldId' => $field->id,
])->orderBy(['path' => 'asc']);

foreach ($query->each() as $component) {
$duplicate = new Component;
$duplicate->id = $component->id;
$duplicate->elementId = $destination->id;
$duplicate->fieldId = $field->id;
$duplicate->dataId = $component->dataId;
$duplicate->sortOrder = $component->sortOrder;
$duplicate->path = $this->remapPath($component->path);
$duplicate->level = $component->level;
$duplicate->slot = $component->slot;
$duplicate->dateCreated = DateTimeHelper::now();
$duplicate->dateUpdated = DateTimeHelper::now();
$duplicate->uid = StringHelper::UUID();
$duplicate->save();

static::$mapping[$component->id] = $duplicate->id;
}

// I'd love to use INSERT INTO components (elementId, fieldId, ...) SELECT * FROM components WHERE elementId= and fieldId=
// but Craft breaks this because they subclass the db->createCommand() and don't allow you to pass
// a query as the second parameter. They look for $columns[dateCreated] on that second param which
// works when setting raw values but not if a query is passed because it tries to $query[dateCreated]
// and Query isn't array-accessible.
//
// $query = Component::find()->select(['fieldId', 'componentId', 'sortOrder', 'path', 'level', 'slot'])->where([
// 'elementId' => $source->id,
// 'fieldId' => $field->id,
// ]);
// $params = [
// 'elementId' => $source->id,
// 'fieldId' => $field->id,
// ];
// Craft::$app->db->createCommand(Craft::$app->db->getQueryBuilder()->insert(Table::COMPONENTS, $query, $params))->execute();
// Craft::$app->db->createCommand()->insert(Table::COMPONENTS, $query);
}

protected function remapPath(?string $path)
{
if ($path === null) {
return null;
}

return collect(explode('/', $path))
->map(function ($segment) use ($path) {
if (! isset(static::$mapping[$segment])) {
throw new \RuntimeException('Could not remap ' . $path . ' because ' . $segment . ' could not be found');
}

return static::$mapping[$segment];
})
->join('/');
}
}
17 changes: 17 additions & 0 deletions src/actions/EditComponentData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace markhuot\keystone\actions;

use markhuot\keystone\models\Component;

class EditComponentData
{
public function handle(Component $component, array $data)
{
$component->data->merge($data);
$component->data->save();
$component->refresh();

return $component;
}
}
57 changes: 57 additions & 0 deletions src/actions/MoveComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace markhuot\keystone\actions;

use markhuot\keystone\models\Component;
use yii\db\Expression;

class MoveComponent
{
public function handle(Component $source, Component $target, string $position)
{
// remove ourselves from the list
Component::updateAll([
'sortOrder' => new Expression('sortOrder - 1')
], ['and',
['=', 'elementId', $source->elementId],
['=', 'fieldId', $source->fieldId],
['path' => $source->path],
['>', 'sortOrder', $source->sortOrder]
]);

// Refresh our target to get the updated/correct sortOrder
$target->refresh();

// make room for the insertion
if ($position === 'above') {
Component::updateAll([
'sortOrder' => new Expression('sortOrder + 1')
], ['and',
['=', 'elementId', $target->elementId],
['=', 'fieldId', $target->fieldId],
['path' => $target->path],
['>=', 'sortOrder', $target->sortOrder]
]);
}
if ($position === 'below')
{
Component::updateAll([
'sortOrder' => new Expression('sortOrder + 1')
], ['and',
['=', 'elementId', $target->elementId],
['=', 'fieldId', $target->fieldId],
['path' => $target->path],
['>', 'sortOrder', $target->sortOrder]
]);
}

// Refresh the target again, in case it changed, so we're setting the correct
// sort order
$target->refresh();
$source->refresh();

$source->path = $target->path;
$source->sortOrder = $position == 'above' ? $target->sortOrder - 1 : $target->sortOrder + 1;
$source->save();
}
}
70 changes: 26 additions & 44 deletions src/controllers/ComponentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public function actionAdd()
$field = Craft::$app->fields->getFieldById($fieldId);
$path = $this->request->getQueryParam('path');
$slot = $this->request->getQueryParam('slot');
$sortOrder = $this->request->getRequiredQueryParam('sortOrder');

return $this->asCpScreen()
->title('Add component')
Expand All @@ -31,46 +32,24 @@ public function actionAdd()
'path' => $path,
'slot' => $slot,
'types' => (new GetComponentType())->all(),
'sortOrder' => $sortOrder,
]);
}

public function actionStore()
{
$componentData = new ComponentData;
$componentData->type = $this->request->getRequiredBodyParam('type');
$componentData->save();

$component = new Component;
$component->elementId = $elementId = $this->request->getRequiredBodyParam('elementId');
$component->fieldId = $fieldId = $this->request->getRequiredBodyParam('fieldId');
$component->dataId = $componentData->id;
$component->path = $path = $this->request->getBodyParam('path');
$component->slot = $this->request->getBodyParam('slot');
$component->type = $this->request->getRequiredBodyParam('type');
$component->sortOrder = ((Component::find()->where([
'elementId' => $elementId,
'fieldId' => $fieldId,
'path' => $component->path,
'slot' => $component->slot,
])->max('sortOrder')) ?? -1) + 1;
$component->save();

$element = Craft::$app->elements->getElementById($component->elementId);
$field = Craft::$app->fields->getFieldById($component->fieldId);

return $component->errors ?
$this->asFailure('Oh no') :
$this->asSuccess('Component added', [
'elementId' => $component->elementId,
'fieldId' => $component->fieldId,
'fieldHandle' => $field->handle,
'fieldHtml' => $field->getInputHtml(null, $element),
]);
return $this->asSuccess('Component added', [
'path' => $this->request->getBodyParam('path'),
'slot' => $this->request->getBodyParam('slot'),
'type' => $this->request->getBodyParam('type'),
'sortOrder' => $this->request->getBodyParam('sortOrder'),
]);
}

public function actionEdit()
{
$id = $this->request->getRequiredQueryParam('id');
$elementId = $this->request->getRequiredQueryParam('elementId');

return $this->asCpScreen()
->title('Edit component')
Expand All @@ -80,27 +59,30 @@ public function actionEdit()
])
->action('keystone/components/update')
->contentTemplate('keystone/edit', [
'component' => Component::findOne(['id' => $id]),
'component' => Component::findOne(['id' => $id, 'elementId' => $elementId]),
]);
}

public function actionUpdate()
{
$id = $this->request->getRequiredBodyParam('id');
$data = $this->request->getBodyParam('fields', []);

$component = Component::findOne(['id' => $id]);
$component->data->merge($data);
$component->data->save();

$element = Craft::$app->elements->getElementById($component->elementId);
$field = Craft::$app->fields->getFieldById($component->fieldId);
// $id = $this->request->getRequiredBodyParam('id');
// $data = $this->request->getBodyParam('fields', []);
//
// $component = Component::findOne(['id' => $id]);
// $component->data->merge($data);
// $component->data->save();
//
// $element = Craft::$app->elements->getElementById($component->elementId);
// $field = Craft::$app->fields->getFieldById($component->fieldId);

return $this->asSuccess('Component saved', [
'elementId' => $component->elementId,
'fieldId' => $component->fieldId,
'fieldHandle' => $field->handle,
'fieldHtml' => $field->getInputHtml(null, $element),
'id' => $this->request->getRequiredBodyParam('id'),
'elementId' => $this->request->getRequiredBodyParam('elementId'),
'fields' => $this->request->getRequiredBodyParam('fields'),
// 'elementId' => $component->elementId,
// 'fieldId' => $component->fieldId,
// 'fieldHandle' => $field->handle,
// 'fieldHtml' => $field->getInputHtml(null, $element),
]);
}

Expand Down
Loading

0 comments on commit 9604a2c

Please sign in to comment.