Como obtener los fields de un content type en Drupal 8

Author Top
enzo

La creación de lógica personalizada para nuestros clientes a veces requiere un cierto nivel de automatización en términos de que nuestra lógica debe ser flexible para soportar los cambios en la estructura de datos.

En Drupal 8 la forma más común para representar los datos es mediante el uso de entidades de tipo nodo, y podemos crear diferentes tipos de tipos de contenido o bundles para las entidades de tipo nodo.

Cada tipo de contenido podría aumentar o disminuir la cantidad de campos, y nuestro código debe estar preparado para manejar esa situación.

Voy a explicarte, cómo conseguir la definición campos de un content type  y como utilizar esa información para representar un objeto de tipo nodo como un array.

1. Obtener definicion de campos de un content type

En primer lugar voy a crear una función para obtener la definición campos para un nombre de máquina de content tupe, naturalmente, puedes implementar esta función como un método dentro de tus clases.

function contentTypeFields($contentType) {
    $entityManager = Drupal::service('entity.manager');
    $fields = [];

    if(!empty($contentType) {
        $fields = array_filter(
            $entityManager->getFieldDefinitions('node', $contentType), function ($field_definition) {
                return $field_definition instanceof FieldConfigInterface;
            }
        );
    }

    return $fields;      
}

En este caso, solo estoy interesado en usar el nombre de la máquina del campo, pero podría hacer un enfoque diferente  y hacer algo con la definición del campo en sí.

Además, utilizo node como un tipo de entidad  pero puede utilizar cualquier entidad, para obtener la definición de sus campos.

2. Convertir nodo en un array

Utilizando el array de definición de campo, podemos obtener todos los valores del nodos y asignarlo a un array. Voy a utilizar un tipo de contenido imaginario llamado ticket.

use Drupal\node\Entity\Node;
use Drupal\field\FieldConfigInterface;

// Load node
$node = Node::load($ticketID);

$fields = contentTypeFields('ticket'); // Replace your content type machine name here.

$ticket['title'] = $node->get('title')->value;
foreach($fields as $fieldID => $field){
    $ticket[$fieldID] = $node->get($fieldID)->getValue();
}

print_r($ticket);

El código anterior producirá una salida similar a la siguiente:

Array
(
    [title] => This is an unassigned ticket
    [field_description] => Array
        (
            [0] => Array
                (
                    [value] => Create a ticket with no one assigned to make sure the system handles it well
                )

        )
    [field_status] => Array
        (
            [0] => Array
                (
                    [target_id] => 2
                )

        )

    [field_ticket_type] => Array
        (
            [0] => Array
                (
                    [target_id] => 9
                )

        )

)

Después de transformar nodo en una inofensivo array, se puede agregar o eliminar cualquier información requerida.

Este tipo de transformación es útil en Drupal 8, para así saltarse alguna validación en el objeto render que evita la inyección de contenido.

Tal estas pensando por qué no utilizar la función get_object_vars, Bueno, todas las propiedades del objeto sin protegidas y sólo se puede acceder mediante el método get. La función get_object_vars solamente puede transformar las propiedades públicas, por lo que no funciona para nuestro propósito.

Otra idea podría ser, transformar objeto de nodo en una array usando el casting, pero si tratas de hacer eso obtendrás una excepción que produce el siguiente mensaje de error.

A fatal error occurred: Could not normalize object of type Drupal\Core\Field\BaseFieldDefinition, no supporting normalizer found.

Espero que hayas encontrado este artículo útil.