Voglio aggiungere un nuovo segmentId (con lo stesso nome) nel mio array di mappatura ma con un elementId diverso ma con lo stesso metodo


14

Di seguito è il MapperInterface.php

Sto cercando di capire come aggiungere un'istruzione if-else nella const. array di mappatura. Qualcosa del genere:

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;
}

Spero che abbia un senso. Non sono sicuro che ci sia un modo migliore per farlo, ma alla fine ho bisogno di più di un segmento "LIN". Forse aggiungi una nuova funzione e usi questa condizione?

NUOVA RISPOSTA FILE ***

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

}

Quindi vuoi che l'array const MAPPING sia dinamico? non puoi farlo con const. È possibile utilizzare un'altra funzione per ottenere quell'array e modificarlo se necessario
dWinder

Davvero non so cosa stai cercando di fare. Cosa vuoi ottenere?
Stephan Vierkant,

Risposte:


6

Come puoi vedere qui - la variabile const non può essere logica di cambiamento o di mantenimento . Nota che l'interfaccia non può contenere anche la logica, quindi non puoi farlo nell'interfaccia.

Penso che la soluzione migliore per il tuo problema sia quella di utilizzare una classe astratta . Sarò lo stesso della tua interfaccia (puoi vedere la discussione sui diversi qui, ma penso che sarà lo stesso per le tue esigenze).

Consiglierei di creare una classe astratta come questa:

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

}

Ora puoi dichiarare l'oggetto ereditato come:

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

Esempio per l'uso è:

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

Nota che sembra che la tua logica non stia cambiando, quindi ho inserito una nuova variabile e l'ho impostata durante il costrutto. Se vuoi puoi scaricarlo e modificare semplicemente il valore di ritorno della getProcessfunzione - inserisci tutta la logica lì.

Un'altra opzione è rendere il $mapToProcesspubblico e accedervi direttamente, ma immagino che una migliore programmazione sia usare il metodo getter.

Spero che aiuti!


Dovrei essere in grado di integrare / aggiungere l'intera classe astratta nel mio stesso file appena sotto l'ultima funzione pubblica map (array $ segmenti): OrderUpdateInterface; } QUI
Singleton,

Quindi ora posso semplicemente sostituire tutto il vecchio codice e usare questa classe astratta? Ho contrassegnato la risposta come corretta e molto utile amico mio. @dWinder
Singleton

Si, puoi. Ci sono differenze tra interfaccia e classe astratta, ma per la maggior parte del caso agisce allo stesso modo (puoi leggerlo nel link all'inizio del post).
dinder

Penso che nella logica debba ancora aggiungere questo corretto? altrimenti if ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton,

1
Dovresti aggiungere anche quello. Ne ho inserito solo un esempio di dove dovrebbe essere la logica. Lo modificherò anche per far sì che il codice lo copra
dWinder

5

Non è possibile aggiungere un'istruzione if-else all'interno della definizione costante. Il più vicino a quello che stai cercando è probabilmente questo:

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

Uscita:

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

In altre parole, dovrai dividere l'array in costanti separate, quindi eseguire tutte le definizioni condizionali, quindi costruire l'array MAPPING finale dai valori costanti risultanti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.