Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save pdaleramirez/681b1fffb082c7ceed8be02f5c7455e8 to your computer and use it in GitHub Desktop.
Save pdaleramirez/681b1fffb082c7ceed8be02f5c7455e8 to your computer and use it in GitHub Desktop.
Duplicate entry migration error for "sebastian-lenz/craft-linkfield" craft cms plugin
<?php
namespace lenz\linkfield\migrations;
use Craft;
use craft\base\FieldInterface;
use craft\db\Migration;
use craft\db\Query;
use craft\db\Table;
use craft\fields\Matrix;
use craft\helpers\Json;
use lenz\linkfield\fields\LinkField;
use lenz\linkfield\records\LinkRecord;
use verbb\supertable\fields\SuperTableField;
/**
* m190417_202153_migrateDataToTable migration.
* @noinspection PhpUnused
*/
class m190417_202153_migrateDataToTable extends Migration
{
/**
* @inheritdoc
*/
public function safeUp(): bool {
if (!$this->db->tableExists(LinkRecord::tableName())) {
(new Install())->safeUp();
}
$this->updateAllSettings();
$this->updateAllFields();
return true;
}
/**
* @inheritdoc
*/
public function safeDown(): bool {
$this->dropTableIfExists(LinkRecord::tableName());
return true;
}
// Private methods
// ---------------
/**
* @return void
*/
private function updateAllFields(): void {
$service = Craft::$app->getFields();
$service->refreshFields();
foreach ($service->getAllFields() as $field) {
$this->updateField($field, Table::CONTENT);
}
}
/**
* @return void
*/
private function updateAllSettings(): void {
$this->update(Table::FIELDS, [
'type' => 'lenz\\linkfield\\fields\\LinkField',
], [
'type' => 'typedlinkfield\\fields\\LinkField'
]);
$rows = (new Query())
->select(['id', 'settings'])
->from(Table::FIELDS)
->where(['type' => 'lenz\\linkfield\\fields\\LinkField'])
->all();
foreach ($rows as $row) {
$this->update(Table::FIELDS, [
'settings' => $this->updateSettings($row['settings'])
], [
'id' => $row['id']
]);
}
}
/**
* @param FieldInterface $field
* @param string $table
* @param string $handlePrefix
*/
private function updateField(FieldInterface $field, string $table, string $handlePrefix = ''): void {
if ($field instanceof LinkField) {
$this->updateLinkField($field, $table, $handlePrefix);
} elseif ($field instanceof Matrix) {
$this->updateMatrixField($field);
} elseif ($field instanceof SuperTableField) {
$this->updateSuperTable($field);
}
}
/**
* @param Matrix $matrixField
*/
private function updateMatrixField(Matrix $matrixField): void {
$table = $matrixField->contentTable;
$blockTypes = Craft::$app
->getMatrix()
->getBlockTypesByFieldId($matrixField->id);
foreach ($blockTypes as $blockType) {
foreach ($blockType->getCustomFields() as $field) {
$this->updateField($field, $table, $blockType->handle.'_');
}
}
}
/**
* @param LinkField $field
* @param string $table
* @param string $handlePrefix
*/
private function updateLinkField(LinkField $field, string $table, string $handlePrefix = ''): void {
$insertRows = [];
$columnName = ($field->columnPrefix ?: 'field_') . $handlePrefix . $field->handle;
if ($field->columnSuffix) {
$columnName .= '_' . $field->columnSuffix;
}
$writeRows = function($rows) {
if (count($rows)) {
foreach ($rows as $row) {
$doesExist = (new Query())
->select('id')
->where(['elementId' => $row[0], 'fieldId' => $row[2]])
->from(LinkRecord::tableName())
->exists();
if ($doesExist) {
continue;
}
$this->insert(LinkRecord::tableName(), [
'elementId' => $row[0],
'siteId' => $row[1],
'fieldId' => $row[2],
'linkedId' => $row[3],
'linkedSiteId' => $row[4],
'type' => $row[5],
'linkedUrl' => $row[6],
'payload' => $row[7],
]);
}
}
};
// Make sure the rows actually exist in the elements table.
$rows = (new Query())
->select(['t.elementId', 't.siteId', 't.'.$columnName])
->from(['t' => $table])
->innerJoin(['e' => Table::ELEMENTS], '[[t.elementId]] = [[e.id]]')
->all();
foreach ($rows as $row) {
$payload = Json::decodeIfJson($row[$columnName]);
try {
if (!is_array($payload)) {
continue;
}
} catch (\Exception $e) {
$message = $e->getMessage();
}
$type = $payload['type'] ?? null;
$value = $payload['value'] ?? '';
unset($payload['type']);
unset($payload['value']);
if ($value && is_numeric($value)) {
$doesExist = (new Query())
->select('id')
->where(['id' => $value])
->from('{{%elements}}')
->exists();
if (!$doesExist) {
$value = null;
}
}
$insertRows[] = [
$row['elementId'], // elementId
$row['siteId'], // siteId
$field->id, // fieldId
is_numeric($value) ? $value : null, // linkedId
is_numeric($value) ? $row['siteId'] : null, // linkedSiteId
$type, // type
is_numeric($value) ? null : $value, // linkedUrl
Json::encode($payload) // payload
];
if (count($insertRows) > 100) {
$writeRows($insertRows);
$insertRows = [];
}
}
$writeRows($insertRows);
$this->dropColumn($table, $columnName);
}
/**
* @param string $settings
* @return string
*/
private function updateSettings(string $settings): string {
$settings = Json::decode($settings);
if (!is_array($settings)) {
$settings = array();
}
if (!array_key_exists('typeSettings', $settings)) {
$settings['typeSettings'] = array();
}
$settings['enableAllLinkTypes'] = false;
if (isset($settings['allowedLinkNames'])) {
$allowedLinkNames = $settings['allowedLinkNames'];
if (!is_array($allowedLinkNames)) {
$allowedLinkNames = [$allowedLinkNames];
}
foreach ($allowedLinkNames as $linkName) {
if ($linkName == '*') {
$settings['enableAllLinkTypes'] = true;
} else {
$settings['typeSettings'][$linkName]['enabled'] = true;
}
}
}
unset($settings['allowedLinkNames']);
return Json::encode($settings);
}
/**
* @param SuperTableField $superTableField
*/
private function updateSuperTable(SuperTableField $superTableField): void {
foreach ($superTableField->getBlockTypeFields() as $field) {
$this->updateField($field, $superTableField->contentTable);
}
}
}
@HAWilliams01
Copy link

Just curious as to what version of Craft you ran this on. I'm on version 3.9.13 and I'm getting Calling unknown method: craft\models\MatrixBlockType::getCustomFields() from your edits above

@HAWilliams01
Copy link

I changed getCustomFields to getFields on 109 and it worked for me!

I forked from version 2.0.0-rc.2 and was on Craft 3.9.13

@pdaleramirez
Copy link
Author

Just curious as to what version of Craft you ran this on. I'm on version 3.9.13 and I'm getting Calling unknown method: craft\models\MatrixBlockType::getCustomFields() from your edits above

I think it was 3.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment