Created
March 11, 2024 23:40
-
-
Save pdaleramirez/681b1fffb082c7ceed8be02f5c7455e8 to your computer and use it in GitHub Desktop.
Duplicate entry migration error for "sebastian-lenz/craft-linkfield" craft cms plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} | |
} |
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
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
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