¿Cuál y por qué es la forma correcta de cargar un modelo?

9

Tengo bastante experiencia con Magento pero me di cuenta de que no entiendo qué forma de cargar un modelo es la correcta y por qué. He leído todo lo que pude sobre el tema, pero las personas que explican cosas como esta nunca profundizan lo suficiente como para explicar por qué usar este método específico en lugar de otro. Supongamos que no hay un repositorio para el modelo que quiero cargar.

Hasta ahora, siempre estaba usando model en constructor y luego simplemente lo cargaba.

public function __construct(
    \Vendor\Module\Model\Something $somethingModel
) {
    $this->somethingModel = $somethingModel;
}

public function getTestById($id) {
    return $this->somethingModel->load($id);
}

Y siempre funcionó según lo previsto, también estoy bastante seguro de que, o al menos se usó comúnmente en el núcleo.

Pero luego vi a uno de mis colegas usando

modelFactory->create()->load($id)

Según tengo entendido, las fábricas se están utilizando para crear una nueva entidad, por ejemplo, si quisiera crear un nuevo producto, puedo crear la fábrica, llenarla con datos y luego guardarla. Pero, de nuevo, comencé a investigar el tema y vi un ejemplo de Fabian Schmengler ( ¿Cuándo deberíamos usar un repositorio y una fábrica en Magento 2? ) Que estaba cargando el modelo de esta manera y también desalentó a otros de simplemente cargar los modelos, no lo hizo. No explique por qué, además de decir que "no forma parte del contrato de servicio". Según tengo entendido, los repositorios son parte de los contratos de servicio, por lo que no veo ninguna conexión aquí cuando se trata de cargar modelos que no están disponibles a través de un repositorio.

Para agregar más confusión, también encontré una forma de cargar el modelo obteniendo el resourceModel de la modelFactory creada, fue presentada por Vinai Kopp ( ¿Cómo implementar un contrato de servicio para un módulo personalizado en Magento 2? ) Y ahora estoy completamente perdido ya que siempre he leído que no debería usar modelos de recursos directamente.

Entonces, sí, ¿podría alguien decirme cuál es la forma correcta y por qué debería usarlo en lugar de todos los otros métodos?

czs
fuente
Literalmente estoy vinculando este hilo con un ejemplo confuso, ¿incluso leíste mi publicación?
czs
1
Buena pregunta, intentaré encontrar tiempo para responder en detalle más adelante. Ya puedo decirle eso: es un caso diferente si carga sus propios modelos (por ejemplo, Vinai) o modelos de los módulos principales o de terceros (mi respuesta). Además, inyectar el modelo a través del constructor le dará la misma instancia cada vez, lo que puede provocar efectos secundarios no deseados.
Fabian Schmengler

Respuestas:

12

Bueno, el primer paso que debe verificar para el modelo en cuestión es: ¿Hay un contrato de servicio de repositorio? Si es así, úselo, porque los contratos de servicio están sujetos a versiones semánticas y continuarán comportándose como deberían hasta que salga Magento 3.x. No es necesario decir que cuando crea sus propios módulos con modelos que requieren persistencia, también debe escribir el repositorio para eso.

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->productRepository = $productRepository;
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $this->productRepository->save($product);
}

Si no hay un repositorio presente, use el modelo de recurso . Tenga en cuenta que los modelos de recursos no contienen un estado: están utilizando la persistencia para sus modelos 'regulares'. Por lo tanto, no es obligatorio incluirlos en una fábrica:

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product $productResource,
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productResource = $productResource;
    $this->productFactory = $productFactory;
    ...
    /** @var \Magento\Catalog\Api\Data\ProductInterface $product */
    $product = $this->productFactory->create();
    $this->productResource->save($product);
}

"Entonces, ¿qué beneficio trae un Contrato / Repositorio de Servicios sobre un Modelo de Recursos?" usted puede preguntar Bueno, en teoría, un Modelo de Recursos solo debería ser responsable de la persistencia de un Modelo de Datos , mientras que un Repositorio también tiene en cuenta las tareas adicionales involucradas al guardar una entidad. Piense en actualizar índices, crear relaciones con otras entidades, etc. Esta es la teoría, aunque en la vida real estas líneas tienden a difuminarse con bastante frecuencia. Pero es bueno para ti tener esto en cuenta.

Usted no debe utilizar los modelos directa save(), load()etc. -Métodos. Están en desuso porque es semánticamente incorrecto. Piénselo de una manera SÓLIDA:

  • (Datos) Los modelos solo deberían ser responsables de contener los datos.
  • Los modelos de recursos deben ser responsables de la persistencia de dichos datos.
  • Los repositorios deben ser responsables de la comunicación dentro y fuera del módulo para acciones de persistencia.

Y es el último punto el que marca la diferencia: cuando se comunica con otros módulos, en un mundo ideal, uno nunca debería tener que confiar en la lógica interna persistente de esos módulos (o cualquiera de sus métodos públicos para el caso, pero esa es otra discusión), pero solo use la funcionalidad que proporcionan los contratos de servicio de los módulos .

En conclusión

Para responder a su pregunta: en orden de preferencia. La forma correcta de cargar un modelo es:

  • Si hay un Repositorio, cárguelo usando el Repositorio.
  • Solo si no hay un Repositorio, use el Modelo de recursos (en combinación con una fábrica).
Giel Berkers
fuente
1
Ok, entonces si sigo correctamente: cuando quiero modificar / agregar nuevos datos y guardarlos en la base de datos, entonces debería usar el Modelo de recursos y cuando quiero cargar datos en la memoria, ¿debería usar Factory? Entonces, ¿hay alguna situación en la que deba usar el modelo regular directamente (como al usar una clase de modelo en el constructor)?
czs
@czs Tienes razón. He agregado un ejemplo más descriptivo para la carga de modelos para el mismo.
Milind Singh
2
  • ModelsLa interfaz de datos se utiliza para mantener solo los datos en objetos, es decir, sety getdatos para una fila.
  • ResourceModelsson un mecanismo que es responsable de la persistencia de dichos datos, es decir, ejecuta la consulta SQL para realmente saveo loaddatos en el Modelobjeto.

La forma correcta loady savedebe ser creando un repositorio o cargando desde un recurso de la siguiente manera:

namespace MyVendor\MyModule\Model;

class QueueRepository impliments \MyVendor\MyModule\Api\QueueRepositoryInterface
{

    /** @var \MyVendor\MyModule\Model\ResourceModel\Queue  */
    public $resource;

    /** @var \MyVendor\MyModule\Model\QueueFactory  */
    public $modelFactory;

    public function __construct(
        \MyVendor\MyModule\Model\ResourceModel\Queue $resource,
        \MyVendor\MyModule\Model\QueueFactory $modelFactory
    ) {
        $this->resource = $resource;
        $this->modelFactory = $modelFactory;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @return $queue
     * @throws \Exception
     */
    public function save(\MyVendor\Integrator\Api\Data\QueueInterface $queue)
    {
        $this->resource->save($queue);
        return $queue;
    }

    /**
     * Save
     * @param \MyVendor\MyModule\Api\Data\QueueInterface $queue
     * @param int $id
     * @return $queue
     * @throws \Exception
     */
    public function load(\MyVendor\MyModule\Api\Data\QueueInterface $queue, $id)
    {
        $this->resource->load($queue, $id);
        return $queue;
    }

    public function getById($id)
    {
        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
    }
}

Aquí, \MyVendor\MyModule\Api\Data\QueueInterfaceestá implementado por QueueModel.

Entonces, detrás de escena, en realidad estamos creando un Modelobjeto y luego loadingel ResourceModelobjeto. Esta es la forma correcta de cargar o guardar.

        $queue = $this->modelFactory->create();
        $this->resource->load($queue, $id);
        return $queue;
Milind Singh
fuente