Quero adicionar um novo segmentId (com o mesmo nome) à minha matriz de mapeamento, mas com um elementId diferente, mas com o mesmo método


14

Abaixo está o MapperInterface.php

Estou tentando descobrir como adicionar uma declaração if-else na const. matriz de mapeamento. Algo assim:

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 faça sentido. Não tenho certeza se existe uma maneira melhor de fazê-lo, mas, em última análise, preciso de mais de 1 segmentoId "LIN". Talvez adicione uma nova função e use essa condição?

NOVA RESPOSTA DE ARQUIVOS ***

    <?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()];
    }

}

Então você quer que o array const MAPPING seja dinâmico? você não pode fazer isso com const. Você pode usar outra função para obter essa matriz e modificar, se necessário
dWinder 16/01

Realmente não sei o que você está tentando fazer. O que você quer alcançar?
Stephan Vierkant 16/01

Respostas:


6

Como você pode ver aqui - a variável const não pode ser alterada ou manter lógica . Observe que a interface não pode conter lógica também - portanto, você não pode fazer isso na sua interface.

Penso que a melhor solução para o seu problema é usar uma classe abstrata . Eu serei o mesmo que sua interface (você pode ver a discussão sobre o diferente aqui, mas acho que será o mesmo para suas necessidades).

Eu recomendaria criar uma classe abstrata 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];
    }

}

Agora você pode declarar o objeto herdado como:

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

Exemplo de uso é:

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

Note que parece que sua lógica não está mudando, então eu coloco uma nova variável e a defino durante a construção. Se você quiser, pode despejá-lo e apenas modificar o valor de retorno da getProcessfunção - coloque toda a lógica lá.

Outra opção é tornar o $mapToProcesspúblico e acessá-lo diretamente, mas acho que uma melhor programação é usar o método getter.

Espero que ajude!


Eu deveria ser capaz de integrar / adicionar toda essa classe abstrata no meu mesmo arquivo logo abaixo da última função map da função pública (array $ segmentos): OrderUpdateInterface; } AQUI
Singleton

Então agora eu posso simplesmente substituir todo o código antigo e usar essa classe abstrata? Marquei a resposta como correta e muito útil, meu amigo. @dWinder
Singleton

Sim você pode. Há diferença entre interface e classe abstrata, mas para a maioria dos casos ela age da mesma maneira (você pode ler sobre isso no link no início do post).
dWinder 16/01

Eu acho que na lógica ainda preciso adicionar isso correto? caso contrário, if ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton

11
Você deve adicionar isso também. Eu apenas coloquei algumas delas como exemplo de onde a lógica deveria estar. Vou editar com isso também para fazer com que o código o cubra
dWinder 21/01

5

Você não pode adicionar uma instrução if-else dentro da definição constante. O mais próximo do que você está procurando é provavelmente o seguinte:

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,
];

Saída:

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

Em outras palavras, você precisará dividir sua matriz em constantes separadas, fazer todas as definições condicionais e construir a matriz MAPPING final a partir dos valores constantes resultantes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.