Ich möchte meinem Mapping-Array eine neue segmentId (mit demselben Namen) hinzufügen, jedoch mit einer anderen elementId, aber derselben Methode

14

Unten ist die MapperInterface.php

Ich versuche herauszufinden, wie man der const eine if-else-Anweisung hinzufügt. Mapping-Array. So etwas wie das:

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

Ich hoffe das ergibt Sinn. Ich bin mir nicht sicher, ob es einen besseren Weg gibt, aber letztendlich brauche ich mehr als 1 "LIN" -Segment-ID. Vielleicht eine neue Funktion hinzufügen und diese Bedingung verwenden?

NEUE DATEI ANTWORT ***

    <?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
quelle
Sie möchten also, dass das MAPPING const-Array dynamisch ist? das kann man mit const nicht machen. Sie können eine andere Funktion verwenden, um dieses Array
abzurufen
Ich weiß wirklich nicht, was Sie versuchen zu tun. Was möchten Sie erreichen?
Stephan Vierkant

Antworten:

6

Wie Sie sehen hier - const Variable kann nicht ändern oder Haltelogik sein . Beachten Sie, dass die Schnittstelle auch keine Logik enthalten kann. Sie können dies also nicht in Ihrer Schnittstelle tun.

Ich denke, die bessere Lösung für Ihr Problem ist die Verwendung einer abstrakten Klasse . Ich werde das gleiche sein wie Ihre Benutzeroberfläche (Sie können die Diskussion über die verschiedenen hier sehen, aber ich denke, es wird das gleiche für Ihre Bedürfnisse sein).

Ich würde empfehlen, eine abstrakte Klasse wie folgt zu erstellen:

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

}

Jetzt können Sie das geerbte Objekt wie folgt deklarieren:

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

Anwendungsbeispiel ist:

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

Beachten Sie, dass sich Ihre Logik anscheinend nicht ändert. Deshalb habe ich eine neue Variable eingefügt und sie während des Konstrukts festgelegt. Wenn Sie möchten, können Sie es sichern und einfach den Rückgabewert der getProcessFunktion ändern - setzen Sie die gesamte Logik dort ab.

Eine andere Möglichkeit ist, die $mapToProcessÖffentlichkeit zu machen und direkt darauf zuzugreifen, aber ich denke, eine bessere Programmierung ist die Verwendung der Getter-Methode.

Ich hoffe, das hilft!

dWinder
quelle
Ich sollte in der Lage sein, diese gesamte abstrakte Klasse in dieselbe Datei direkt unter der öffentlichen Funktionszuordnung der letzten Funktion (Array $ segmente) zu integrieren / hinzuzufügen: OrderUpdateInterface; } HIER
Singleton
Also kann ich jetzt einfach den ganzen alten Code überschreiben und diese abstrakte Klasse verwenden? Ich habe die Antwort als richtig und sehr hilfreich markiert, mein Freund. @dWinder
Singleton
Ja, du kannst. Es gibt Unterschiede zwischen der Schnittstelle und der abstrakten Klasse, aber in den meisten Fällen verhält es sich gleich (Sie können dies im Link am Anfang des Beitrags nachlesen).
dWinder
Ich denke in der Logik muss ich das noch richtig hinzufügen? sonst wenn ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton
1
Sie sollten das auch hinzufügen. Ich habe nur einige davon als Beispiel dafür angeführt, wo die Logik sein sollte. Ich werde auch damit bearbeiten, damit der Code es
abdeckt
5

Sie können der if-else-Anweisung keine if-else-Anweisung hinzufügen. Das, was Sie am nächsten suchen, ist wahrscheinlich das Folgende:

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

Wird ausgegeben:

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

Mit anderen Worten, Sie müssen Ihr Array in separate Konstanten aufteilen, dann alle bedingten Definitionen vornehmen und dann das endgültige MAPPING-Array aus den resultierenden Konstantenwerten erstellen.

Karolis
quelle