added migrate attributes
This commit is contained in:
parent
64ddd5bb01
commit
fb21111ab2
|
|
@ -28,6 +28,7 @@ public function index()
|
|||
$m2CategoriesNotInM1 = $this->migrationService->getM2CategoriesNotInM1();
|
||||
$m1Attributes = $this->migrationService->getMagento1Attributes();
|
||||
$m2Attributes = $this->migrationService->getMagento2Attributes();
|
||||
$m1AttributesMissingInM2 = $this->migrationService->getM1AttributesMissingInM2();
|
||||
$m1AttributeGroups = $this->migrationService->getMagento1AttributeGroups();
|
||||
$m2AttributeGroups = $this->migrationService->getMagento2AttributeGroups();
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ public function index()
|
|||
'm2CategoriesNotInM1' => $m2CategoriesNotInM1,
|
||||
'm1Attributes' => $m1Attributes,
|
||||
'm2Attributes' => $m2Attributes,
|
||||
'm1AttributesMissingInM2' => $m1AttributesMissingInM2,
|
||||
'm1AttributeGroups' => $m1AttributeGroups,
|
||||
'm2AttributeGroups' => $m2AttributeGroups,
|
||||
]);
|
||||
|
|
@ -176,6 +178,26 @@ public function renameCategory(Request $request, $categoryId)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate an attribute from Magento 1 to Magento 2
|
||||
*/
|
||||
public function migrateAttribute(Request $request, $attributeId)
|
||||
{
|
||||
try {
|
||||
$result = $this->migrationService->migrateAttribute($attributeId);
|
||||
|
||||
return response()->json($result, $result['success'] ? 200 : 400);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Attribute migration error: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Migration failed: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the migration
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1030,6 +1030,154 @@ public function getMagento2Attributes()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attributes that exist in Magento 1 but are missing in Magento 2
|
||||
*/
|
||||
public function getM1AttributesMissingInM2()
|
||||
{
|
||||
try {
|
||||
$m1Attributes = $this->getMagento1Attributes();
|
||||
$m2Attributes = $this->getMagento2Attributes();
|
||||
|
||||
// Get all M2 attribute codes
|
||||
$m2AttributeCodes = $m2Attributes->pluck('attribute_code')->toArray();
|
||||
|
||||
// Filter M1 attributes that don't exist in M2
|
||||
$missingAttributes = $m1Attributes->filter(function ($attr) use ($m2AttributeCodes) {
|
||||
return !in_array($attr->attribute_code, $m2AttributeCodes);
|
||||
});
|
||||
|
||||
return $missingAttributes->values();
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error fetching missing attributes: ' . $e->getMessage());
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate an attribute from Magento 1 to Magento 2
|
||||
*/
|
||||
public function migrateAttribute($m1AttributeId)
|
||||
{
|
||||
try {
|
||||
// Get M1 entity type ID
|
||||
$m1EntityTypeId = DB::connection($this->magento1Connection)
|
||||
->table($this->magento1Prefix . 'eav_entity_type')
|
||||
->where('entity_type_code', 'catalog_category')
|
||||
->value('entity_type_id');
|
||||
|
||||
if (!$m1EntityTypeId) {
|
||||
return ['success' => false, 'message' => 'Magento 1 entity type not found'];
|
||||
}
|
||||
|
||||
// Get full attribute data from M1
|
||||
$m1Attribute = DB::connection($this->magento1Connection)
|
||||
->table($this->magento1Prefix . 'eav_attribute')
|
||||
->where('attribute_id', $m1AttributeId)
|
||||
->where('entity_type_id', $m1EntityTypeId)
|
||||
->first();
|
||||
|
||||
if (!$m1Attribute) {
|
||||
return ['success' => false, 'message' => 'Attribute not found in Magento 1'];
|
||||
}
|
||||
|
||||
// Check if attribute already exists in M2
|
||||
$m2EntityTypeId = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_entity_type')
|
||||
->where('entity_type_code', 'catalog_category')
|
||||
->value('entity_type_id');
|
||||
|
||||
if (!$m2EntityTypeId) {
|
||||
return ['success' => false, 'message' => 'Magento 2 entity type not found'];
|
||||
}
|
||||
|
||||
$existingAttribute = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_attribute')
|
||||
->where('entity_type_id', $m2EntityTypeId)
|
||||
->where('attribute_code', $m1Attribute->attribute_code)
|
||||
->first();
|
||||
|
||||
if ($existingAttribute) {
|
||||
return ['success' => false, 'message' => 'Attribute already exists in Magento 2'];
|
||||
}
|
||||
|
||||
DB::connection($this->magento2Connection)->beginTransaction();
|
||||
|
||||
// Insert attribute into M2
|
||||
$m2AttributeId = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_attribute')
|
||||
->insertGetId([
|
||||
'entity_type_id' => $m2EntityTypeId,
|
||||
'attribute_code' => $m1Attribute->attribute_code,
|
||||
'attribute_model' => $m1Attribute->attribute_model ?? null,
|
||||
'backend_model' => $m1Attribute->backend_model ?? null,
|
||||
'backend_type' => $m1Attribute->backend_type,
|
||||
'backend_table' => $m1Attribute->backend_table ?? null,
|
||||
'frontend_model' => $m1Attribute->frontend_model ?? null,
|
||||
'frontend_input' => $m1Attribute->frontend_input ?? null,
|
||||
'frontend_label' => $m1Attribute->frontend_label ?? null,
|
||||
'frontend_class' => $m1Attribute->frontend_class ?? null,
|
||||
'source_model' => $m1Attribute->source_model ?? null,
|
||||
'is_required' => $m1Attribute->is_required ?? 0,
|
||||
'is_user_defined' => $m1Attribute->is_user_defined ?? 1,
|
||||
'default_value' => $m1Attribute->default_value ?? null,
|
||||
'is_unique' => $m1Attribute->is_unique ?? 0,
|
||||
'note' => $m1Attribute->note ?? null,
|
||||
]);
|
||||
|
||||
// Add attribute to default attribute set if it exists
|
||||
$defaultAttributeSet = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_attribute_set')
|
||||
->where('entity_type_id', $m2EntityTypeId)
|
||||
->where('attribute_set_name', 'Default')
|
||||
->first();
|
||||
|
||||
if ($defaultAttributeSet) {
|
||||
$defaultGroup = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_attribute_group')
|
||||
->where('attribute_set_id', $defaultAttributeSet->attribute_set_id)
|
||||
->orderBy('sort_order')
|
||||
->first();
|
||||
|
||||
if ($defaultGroup) {
|
||||
// Get max sort order for this group
|
||||
$maxSortOrder = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_entity_attribute')
|
||||
->where('attribute_set_id', $defaultAttributeSet->attribute_set_id)
|
||||
->where('attribute_group_id', $defaultGroup->attribute_group_id)
|
||||
->max('sort_order') ?? 0;
|
||||
|
||||
// Add attribute to entity_attribute table
|
||||
DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'eav_entity_attribute')
|
||||
->insert([
|
||||
'entity_type_id' => $m2EntityTypeId,
|
||||
'attribute_set_id' => $defaultAttributeSet->attribute_set_id,
|
||||
'attribute_group_id' => $defaultGroup->attribute_group_id,
|
||||
'attribute_id' => $m2AttributeId,
|
||||
'sort_order' => $maxSortOrder + 10,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::connection($this->magento2Connection)->commit();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'Attribute migrated successfully',
|
||||
'attribute_code' => $m1Attribute->attribute_code,
|
||||
'm2_attribute_id' => $m2AttributeId,
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
if (isset($this->magento2Connection)) {
|
||||
DB::connection($this->magento2Connection)->rollBack();
|
||||
}
|
||||
Log::error("Error migrating attribute {$m1AttributeId}: " . $e->getMessage());
|
||||
return ['success' => false, 'message' => 'Failed to migrate attribute: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attribute groups from Magento 1
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -821,6 +821,71 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Missing Attributes Section -->
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>⚠️ Magento 1 Attributes Missing in Magento 2</h2>
|
||||
<p>These attributes exist in Magento 1 but do not have a matching attribute code in Magento 2:</p>
|
||||
@if($m1AttributesMissingInM2->count() > 0)
|
||||
<div style="margin-top: 15px; max-height: 400px; overflow-y: auto;">
|
||||
<table style="width: 100%; border-collapse: collapse; background: white; border-radius: 6px;">
|
||||
<thead>
|
||||
<tr style="background: #f8f9fa; border-bottom: 2px solid #dee2e6;">
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">ID</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Attribute Code</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Label</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Type</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Input</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Required</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">User Defined</th>
|
||||
<th style="padding: 12px; text-align: left; font-weight: 600; color: #333;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="missingAttributesTableBody">
|
||||
@foreach($m1AttributesMissingInM2 as $attr)
|
||||
<tr id="attr-row-{{ $attr->attribute_id }}" style="border-bottom: 1px solid #dee2e6;">
|
||||
<td style="padding: 10px 12px;">{{ $attr->attribute_id }}</td>
|
||||
<td style="padding: 10px 12px; font-weight: 500; color: #667eea;">{{ $attr->attribute_code }}</td>
|
||||
<td style="padding: 10px 12px;">{{ $attr->frontend_label ?? 'N/A' }}</td>
|
||||
<td style="padding: 10px 12px; color: #666;">{{ $attr->backend_type ?? 'N/A' }}</td>
|
||||
<td style="padding: 10px 12px; color: #666;">{{ $attr->frontend_input ?? 'N/A' }}</td>
|
||||
<td style="padding: 10px 12px;">
|
||||
@if($attr->is_required ?? 0)
|
||||
<span style="color: #d32f2f; font-weight: 600;">Yes</span>
|
||||
@else
|
||||
<span style="color: #666;">No</span>
|
||||
@endif
|
||||
</td>
|
||||
<td style="padding: 10px 12px;">
|
||||
@if($attr->is_user_defined ?? 0)
|
||||
<span style="color: #1976D2; font-weight: 600;">Yes</span>
|
||||
@else
|
||||
<span style="color: #666;">No</span>
|
||||
@endif
|
||||
</td>
|
||||
<td style="padding: 10px 12px;">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
onclick="migrateAttribute({{ $attr->attribute_id }}, '{{ $attr->attribute_code }}')"
|
||||
id="migrate-btn-{{ $attr->attribute_id }}"
|
||||
style="padding: 6px 12px; font-size: 0.85em; background: #1976D2; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
||||
Migrate
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="missingAttributesCount" style="margin-top: 15px; padding: 12px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;">
|
||||
<strong>Total:</strong> <span id="missingAttributesTotal">{{ $m1AttributesMissingInM2->count() }}</span> {{ Str::plural('attribute', $m1AttributesMissingInM2->count()) }} found in Magento 1 but not in Magento 2.
|
||||
</div>
|
||||
@else
|
||||
<div style="margin-top: 15px; padding: 15px; background: #d4edda; border-left: 4px solid #28a745; border-radius: 4px; color: #155724;">
|
||||
✓ All Magento 1 attributes have matching attribute codes in Magento 2.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Category Attributes Section -->
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>📋 Category Attributes</h2>
|
||||
|
|
@ -1182,6 +1247,75 @@ function deleteCategory(categoryId, categoryName, source) {
|
|||
});
|
||||
}
|
||||
|
||||
function migrateAttribute(attributeId, attributeCode) {
|
||||
if (!confirm(`Are you sure you want to migrate the attribute "${attributeCode}" from Magento 1 to Magento 2?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const button = document.getElementById(`migrate-btn-${attributeId}`);
|
||||
const originalText = button.textContent;
|
||||
button.disabled = true;
|
||||
button.textContent = 'Migrating...';
|
||||
button.style.background = '#999';
|
||||
button.style.cursor = 'not-allowed';
|
||||
|
||||
const url = `{{ route("migration.migrate-attribute", ["attributeId" => ":id"]) }}`.replace(':id', attributeId);
|
||||
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove the row from the table
|
||||
const row = document.getElementById(`attr-row-${attributeId}`);
|
||||
if (row) {
|
||||
row.style.opacity = '0.5';
|
||||
row.style.background = '#d4edda';
|
||||
|
||||
// Update button to show success
|
||||
button.textContent = 'Migrated ✓';
|
||||
button.style.background = '#28a745';
|
||||
button.disabled = true;
|
||||
|
||||
// Update count
|
||||
const totalSpan = document.getElementById('missingAttributesTotal');
|
||||
if (totalSpan) {
|
||||
const currentCount = parseInt(totalSpan.textContent);
|
||||
if (currentCount > 0) {
|
||||
totalSpan.textContent = currentCount - 1;
|
||||
const countDiv = document.getElementById('missingAttributesCount');
|
||||
if (countDiv && currentCount - 1 === 0) {
|
||||
countDiv.innerHTML = '<strong>Total:</strong> 0 attributes found in Magento 1 but not in Magento 2.';
|
||||
} else if (countDiv) {
|
||||
const plural = (currentCount - 1) === 1 ? 'attribute' : 'attributes';
|
||||
countDiv.innerHTML = `<strong>Total:</strong> ${currentCount - 1} ${plural} found in Magento 1 but not in Magento 2.`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
alert('Attribute migrated successfully!');
|
||||
} else {
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
button.style.background = '#1976D2';
|
||||
button.style.cursor = 'pointer';
|
||||
alert('Error: ' + (data.message || 'Failed to migrate attribute'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
button.style.background = '#1976D2';
|
||||
button.style.cursor = 'pointer';
|
||||
alert('Error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
// Render tree structure
|
||||
function renderTree(container, nodes, source = 'm2') {
|
||||
nodes.forEach(node => {
|
||||
|
|
|
|||
|
|
@ -16,4 +16,5 @@
|
|||
Route::get('/magento2-category-tree', [MagentoMigrationController::class, 'getMagento2CategoryTree'])->name('migration.magento2-category-tree');
|
||||
Route::delete('/category/{categoryId}', [MagentoMigrationController::class, 'deleteCategory'])->name('migration.delete-category');
|
||||
Route::put('/category/{categoryId}/rename', [MagentoMigrationController::class, 'renameCategory'])->name('migration.rename-category');
|
||||
Route::post('/attribute/{attributeId}/migrate', [MagentoMigrationController::class, 'migrateAttribute'])->name('migration.migrate-attribute');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue