Je veux ajouter un nouveau segmentId (avec le même nom) dans mon tableau de mappage mais avec un elementId différent mais la même méthode

14

Ci-dessous est le MapperInterface.php

J'essaie de comprendre comment ajouter une instruction if-else dans la const. tableau de mappage. Quelque chose comme ça:

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

J'espère que cela à du sens. Je ne sais pas s'il y a une meilleure façon de procéder, mais finalement j'ai besoin de plus de 1 segmentId "LIN". Peut-être ajouter une nouvelle fonction et utiliser cette condition?

NOUVELLE RÉPONSE AU FICHIER ***

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

}
Singleton
la source
Vous voulez donc que le tableau de const MAPPING soit dynamique? vous ne pouvez pas faire cela avec const. Vous pouvez utiliser une autre fonction pour obtenir ce tableau et le modifier si nécessaire
dWinder
Je ne sais vraiment pas ce que vous essayez de faire. Que veux-tu accomplir?
Stephan Vierkant

Réponses:

6

Comme vous pouvez le voir ici - la variable const ne peut pas être modifiée ou maintenue logique . Notez que l'interface ne peut pas contenir la logique également - vous ne pouvez donc pas le faire dans votre interface.

Je pense que la meilleure solution pour votre problème est d'utiliser une classe abstraite . Je serai le même que votre interface (vous pouvez voir la discussion sur les différents ici mais je pense que ce sera le même pour vos besoins).

Je recommanderais de créer une classe abstraite comme ceci:

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

}

Vous pouvez maintenant déclarer un objet hérité comme:

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

Exemple d'utilisation:

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

Notez qu'il semble que votre logique ne change pas, j'ai donc mis une nouvelle variable et je l'ai définie pendant la construction. Si vous le souhaitez, vous pouvez le vider et simplement modifier la valeur de retour de la getProcessfonction - y mettre toute la logique.

Une autre option consiste à rendre le $mapToProcesspublic et à y accéder directement, mais je suppose que la meilleure programmation consiste à utiliser la méthode getter.

J'espère que cela pourra aider!

dWinder
la source
Je devrais être en mesure d'intégrer / ajouter cette classe abstraite entière dans mon même fichier juste en dessous de la dernière carte de fonction publique de fonction (segments $ de tableau): OrderUpdateInterface; } ICI
Singleton
Alors maintenant, je peux simplement remplacer tout l'ancien code et utiliser cette classe abstraite? J'ai marqué la réponse comme correcte et très utile mon ami. @dWinder
Singleton
Oui, vous pouvez. Il existe une différence entre l'interface et la classe abstraite, mais dans la majorité des cas, il en va de même (vous pouvez le lire dans le lien au début de l'article).
dWinder
Je pense que dans la logique, je dois encore ajouter cela correctement? sinon si ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton
1
Vous devriez également ajouter cela. Je n'en ai mis qu'une partie comme exemple de la logique. Je vais également éditer avec cela pour que le code le couvre
dWinder
5

Vous ne pouvez pas ajouter une instruction if-else dans la définition constante. Le plus proche de ce que vous recherchez est probablement celui-ci:

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

Sortira:

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

En d'autres termes, vous devrez séparer votre tableau en constantes distinctes, puis effectuer toutes les définitions conditionnelles, puis construire le tableau MAPPING final à partir des valeurs constantes résultantes.

Karolis
la source