Corrige erros de definição de biblioteca e esgotamento de memória no MSC 2020

Remove entrada de biblioteca vazia 'msc_term_select_widget' que causava
IncompleteLibraryDefinitionException. Otimiza buildTermData() para não
instanciar 597 entidades de taxonomia completas: usa loadTree() sem
entidades e busca field_msc_code diretamente na tabela do campo,
eliminando o fatal de memória esgotada (128 MB) ao abrir o modal
de configuração do campo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 07:47:45 -03:00
parent d14aa22445
commit 1d4d676fa6
2 changed files with 35 additions and 21 deletions

View File

@@ -1,6 +1,3 @@
msc_term_select_widget:
version: VERSION
msc_term_list:
version: VERSION
css:

View File

@@ -4,6 +4,7 @@ namespace Drupal\site_tools_msc_2020\Plugin\Field\FieldWidget;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
@@ -42,6 +43,7 @@ class MscTermSelectWidget extends WidgetBase {
array $settings,
array $third_party_settings,
protected EntityTypeManagerInterface $entityTypeManager,
protected Connection $database,
) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
}
@@ -54,6 +56,7 @@ class MscTermSelectWidget extends WidgetBase {
$configuration['settings'],
$configuration['third_party_settings'],
$container->get('entity_type.manager'),
$container->get('database'),
);
}
@@ -260,6 +263,9 @@ class MscTermSelectWidget extends WidgetBase {
/**
* Carrega todos os termos msc_2020 e retorna arrays por nível.
*
* Usa loadTree() sem entidades completas e busca field_msc_code direto na
* tabela do campo, evitando instanciar 597 objetos de entidade.
*
* @return array{
* l1: array<int,string>,
* l2: array<int,array<int,string>>,
@@ -267,48 +273,59 @@ class MscTermSelectWidget extends WidgetBase {
* }
*/
protected function buildTermData(int $max_depth): array {
// Stubs leves: têm tid e name, sem carregar campos personalizados.
$tree = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadTree('msc_2020', 0, NULL, TRUE);
->loadTree('msc_2020', 0, NULL, FALSE);
// Busca todos os valores de field_msc_code em uma única query.
$codes = $this->database
->select('taxonomy_term__field_msc_code', 'c')
->fields('c', ['entity_id', 'field_msc_code_value'])
->execute()
->fetchAllKeyed();
// Indexa os stubs por tid.
$stubs = [];
foreach ($tree as $stub) {
$stubs[(int) $stub->tid] = $stub;
}
$code_to_tid = [];
$l1 = [];
$l2 = [];
$l3 = [];
// Primeira passagem: monta mapa código→TID e coleta L1.
foreach ($tree as $term) {
$code = $term->get('field_msc_code')->value;
$tid = (int) $term->id();
foreach ($stubs as $tid => $stub) {
$code = $codes[$tid] ?? '';
if ($code === '') {
continue;
}
$code_to_tid[$code] = $tid;
if (strlen($code) === 2) {
$l1[$tid] = $code . ' — ' . $term->label();
$l1[$tid] = $code . ' — ' . $stub->name;
}
}
if ($max_depth >= 2) {
foreach ($tree as $term) {
$code = $term->get('field_msc_code')->value;
foreach ($stubs as $tid => $stub) {
$code = $codes[$tid] ?? '';
if (strlen($code) === 3) {
$parent_code = substr($code, 0, 2);
$parent_tid = $code_to_tid[$parent_code] ?? NULL;
$parent_tid = $code_to_tid[substr($code, 0, 2)] ?? NULL;
if ($parent_tid !== NULL) {
$tid = (int) $term->id();
$l2[$parent_tid][$tid] = $code . ' — ' . $term->label();
$l2[$parent_tid][$tid] = $code . ' — ' . $stub->name;
}
}
}
}
if ($max_depth >= 3) {
foreach ($tree as $term) {
$code = $term->get('field_msc_code')->value;
foreach ($stubs as $tid => $stub) {
$code = $codes[$tid] ?? '';
if (strlen($code) === 5) {
$parent_code = substr($code, 0, 3);
$parent_tid = $code_to_tid[$parent_code] ?? NULL;
$parent_tid = $code_to_tid[substr($code, 0, 3)] ?? NULL;
if ($parent_tid !== NULL) {
$tid = (int) $term->id();
$l3[$parent_tid][$tid] = $code . ' — ' . $term->label();
$l3[$parent_tid][$tid] = $code . ' — ' . $stub->name;
}
}
}