Quiero agregar un nuevo ID de segmento (con el mismo nombre) en mi matriz de mapeo pero con un ID de elemento diferente pero el mismo método

14

A continuación se muestra el MapperInterface.php

Estoy tratando de descubrir cómo agregar una declaración if-else en la constante. matriz de mapeo. Algo así:

if (LIN02 == VN”) 
o   Treat LIN03 as the SKU
·         else if (LIN04 == VN”) 
o   Treat LIN05 as the SKU

<?php

declare(strict_types=1);

namespace Direct\OrderUpdate\Api;

use Direct\OrderUpdate\Api\OrderUpdateInterface;

/**
 * Interface MapperInterface
 * Translates parsed edi file data to a \Direct\OrderUpdate\Api\OrderUpdateInterface
 * @package Direct\OrderUpdate\Api
 */
interface MapperInterface
{
    /**
     * Mapping array formatted as MAPPING[segemntId][elemntId] => methodNameToProcessTheValueOfElement
     * @var array
     */
    const MAPPING = [
        'DTM' => ['DTM02' => 'processCreatedAt'],   // shipment.created_at
        'PRF' => ['PRF01' => 'processIncrementId'], // order.increment_id
        'LIN' => ['LIN05' => 'processSku'],         // shipment.items.sku
        'SN1' => ['SN102' => 'processQty'],         // shipment.items.qty
        'REF' => ['REF02' => 'processTrack']        // shipment.tracks.track_number, shipment.tracks.carrier_code
    ];

    /**
     * Mapping for carrier codes
     * @var array
     */
    const CARRIER_CODES_MAPPING = ['FED' => 'fedex'];

    /**
     * @return array
     */
    public function getMapping(): array;

    /**
     * @param array $segments
     * @return OrderUpdateInterface
     */
    public function map(array $segments): OrderUpdateInterface;
}

Espero que tenga sentido. No estoy seguro de si hay una mejor manera de hacerlo, pero finalmente necesito más de 1 ID de segmento "LIN". ¿Quizás agregar una nueva función y usar esta condición?

NUEVA RESPUESTA DE ARCHIVO ***

    <?php

    declare(strict_types=1);

    namespace Direct\OrderUpdate\Api;

    use Direct\OrderUpdate\Api\OrderUpdateInterface;

    /**
     * Abstract Mapper
     * Translates parsed edi file data to a \Direct\OrderUpdate\Api\OrderUpdateInterface
     * @package Direct\OrderUpdate\Api
     */

    abstract class AbstractMapper{
    // Here we add all the methods from our interface as abstract
    public abstract function getMapping(): array;
    public abstract function map(array $segments): OrderUpdateInterface;

    // The const here will behave the same as in the interface
    const CARRIER_CODES_MAPPING = ['FED' => 'fedex'];

    // We will set our default mapping - notice these are private to disable access from outside
    private const MAPPING = ['LIN' => [
    'LIN02' => 'VN',
    'LIN01' => 'processSku'],
    'PRF' => ['PRF01' => 'processIncrementId'],
    'DTM' => ['DTM02' => 'processCreatedAt'],
    'SN1' => ['SN102' => 'processQty'],
    'REF' => ['REF02' => 'processTrack']];

    private $mapToProcess = [];

    // When we initiate this class we modify our $mapping member according to our new logic
    function __construct() {
    $this->mapToProcess = self::MAPPING; // init as
    if ($this->mapToProcess['LIN']['LIN02'] == 'VN')
    $this->mapToProcess['LIN']['LIN03'] = 'processSku';
    else if ($this->mapToProcess['LIN']['LIN04'] == 'VN')
        $this->mapToProcess['LIN']['LIN05'] = 'processSku';
    }

    // We use this method to get our process and don't directly use the map
    public function getProcess($segemntId, $elemntId) {
    return $this->mapToProcess[$segemntId][$elemntId];
    }

   }

class Obj extends AbstractMapper {
    // notice that as interface it need to implement all the abstract methods
    public function getMapping() : array {
        return [$this->getMapping()];
    }
    public function map() : array {
        return [$this->map()];
    }

}

class Obj extends AbstractMapper {
    // notice that as interface it need to implement all the abstract methods
    public function getMapping() : array {
        return [$this->getMapping()];
    }
    public function map() : array {
        return [$this->map()];
    }

}
único
fuente
Entonces, ¿quieres que la matriz const MAPPING sea dinámica? no puedes hacer eso con const. Puede usar otra función para obtener esa matriz y modificarla si es necesario
dWinder
Realmente no sé lo que estás tratando de hacer. ¿Qué quieres lograr?
Stephan Vierkant

Respuestas:

6

Como puede ver aquí , la variable const no se puede cambiar ni mantener la lógica . Tenga en cuenta que la interfaz no puede contener lógica también, por lo que no puede hacerlo en su interfaz.

Creo que la mejor solución para su problema es usar una clase abstracta . Seré el mismo que su interfaz (puede ver la discusión sobre los diferentes aquí, pero creo que será lo mismo para sus necesidades).

Recomendaría crear una clase abstracta como esta:

abstract class AbstractMapper{
    // here add all the method from your interface as abstract
    public abstract function getMapping(): array;
    public abstract function map(array $segments): OrderUpdateInterface;

    // the const here will behave the same as in the interface
    const CARRIER_CODES_MAPPING = ['FED' => 'fedex'];

    // set your default mapping - notice those are private to disable access from outside
    private const MAPPING = ['LIN' => [
                                'LIN02' => 'NV', 
                                'LIN01' => 'processSku'], 
                             'PRF' => [
                                'PRF01' => 'processIncrementId']];
    private $mapToProcess = [];


    // when initiate this class modify your $mapping member according your logic
    function __construct() {
        $this->mapToProcess = self::MAPPING; // init as 
        if ($this->mapToProcess['LIN']['LIN02'] == 'NV')
            $this->mapToProcess['LIN']['LIN03'] = 'processSku';
        else if ($this->mapToProcess['LIN']['LIN04'] == 'NV')
            $this->mapToProcess['LIN']['LIN05'] = 'processSku';
     }

    // use method to get your process and don't use directly the map
    public function getProcess($segemntId, $elemntId) {
        return $this->mapToProcess[$segemntId][$elemntId];
    }

}

Ahora puede declarar el objeto que heredó como:

class Obj extends AbstractMapper {
    // notice that as interface it need to implement all the abstract methods
    public function getMapping() : array {
        return [];
    }
}

Ejemplo de uso es:

$obj  = New Obj();
print_r($obj->getProcess('LIN', 'LIN01'));

Tenga en cuenta que parece que su lógica no está cambiando, así que pongo una nueva variable y la configuro durante la construcción. Si lo desea, puede volcarlo y simplemente modificar el valor de retorno de la getProcessfunción: coloque toda la lógica allí.

Otra opción es hacer $mapToProcesspúblico y acceder a él directamente, pero supongo que una mejor programación es usar el método getter.

¡Espero que ayude!

dWinder
fuente
Debería poder integrar / agregar toda esa clase abstracta en mi mismo archivo, justo debajo de la última función de mapa de funciones públicas (matriz $ segmentos): OrderUpdateInterface; } AQUÍ
Singleton
Entonces, ¿puedo anular todo el código anterior y usar esta clase abstracta? Marqué la respuesta como correcta y muy útil mi amigo. @dWinder
Singleton
Sí tu puedes. Hay una diferencia entre la interfaz y la clase abstracta, pero para la mayoría de los casos actúa igual (puede leer sobre esto en el enlace al comienzo de la publicación).
dWinder
Creo que en la lógica todavía necesito agregar esto ¿correcto? si no ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton
1
Deberías agregar eso también. Solo pongo algo de eso como ejemplo de dónde debería estar la lógica. También
editaré
5

No puede agregar una instrucción if-else dentro de la definición constante. Lo más cercano a lo que está buscando es probablemente esto:

const A = 1;
const B = 2;

// Value of C is somewhat "more dynamic" and depends on values of other constants
const C = self::A == 1 ? self::A + self::B : 0;

// MAPPING array inherits "more dynamic" properties of C
const MAPPING = [
    self::A,
    self::B,
    self::C,
];

Saldrá:

0 => 1
1 => 2
2 => 3

En otras palabras, deberá dividir su matriz en constantes separadas, luego hacer todas las definiciones condicionales, luego construir la matriz MAPPING final a partir de los valores constantes resultantes.

Karolis
fuente