Saya ingin menambahkan segmentId baru (dengan nama yang sama) ke dalam array pemetaan saya tetapi dengan elementId yang berbeda tetapi metode yang sama

14

Di bawah ini adalah MapperInterface.php

Saya mencoba mencari cara untuk menambahkan pernyataan if-else ke dalam const. array pemetaan. Sesuatu seperti itu:

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

Saya harap itu masuk akal. Tidak yakin apakah ada cara yang lebih baik untuk melakukannya, tetapi pada akhirnya saya membutuhkan lebih dari 1 "LIN" segmentId. Mungkin menambahkan fungsi baru dan menggunakan kondisi ini?

JAWABAN FILE BARU ***

    <?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
sumber
Jadi Anda ingin array const pemetaan menjadi dinamis? Anda tidak dapat melakukannya dengan const. Anda dapat menggunakan fungsi lain untuk mendapatkan array itu dan memodifikasi jika diperlukan
dWinder
Saya benar-benar tidak tahu apa yang Anda coba lakukan. Apa yang ingin Anda capai?
Stephan Vierkant

Jawaban:

6

Seperti yang Anda lihat di sini - variabel const tidak dapat diubah atau ditahan logika . Perhatikan bahwa antarmuka tidak dapat menahan logika juga - jadi Anda tidak dapat melakukannya di antarmuka Anda.

Saya pikir solusi yang lebih baik untuk masalah Anda adalah dengan menggunakan kelas abstrak . Saya akan sama dengan antarmuka Anda (Anda dapat melihat diskusi tentang perbedaan di sini tapi saya pikir itu akan sama dengan kebutuhan Anda).

Saya akan merekomendasikan untuk membuat kelas abstrak karena ini:

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

}

Sekarang Anda dapat mendeklarasikan objek yang diwarisi sebagai:

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

Contoh untuk digunakan adalah:

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

Perhatikan bahwa tampaknya logika Anda tidak berubah, jadi saya meletakkan variabel baru dan mengaturnya selama pembuatan. Jika mau, Anda dapat membuangnya dan hanya memodifikasi nilai pengembalian getProcessfungsi - letakkan semua logika di sana.

Pilihan lain adalah membuat $mapToProcesspublik dan mengaksesnya secara langsung tetapi saya kira pemrograman yang lebih baik adalah dengan menggunakan metode pengambil.

Semoga itu bisa membantu!

dWinder
sumber
Saya harus dapat mengintegrasikan / menambahkan seluruh kelas abstrak dalam file saya yang sama tepat di bawah peta fungsi publik fungsi terakhir (array $ segment): OrderUpdateInterface; } DI SINI
Singleton
Jadi sekarang saya bisa mengganti semua kode lama dan menggunakan kelas abstrak ini? Saya menandai jawabannya sebagai benar dan sangat membantu teman saya. @dWinder
Singleton
Ya kamu bisa. Ada perbedaan antara antarmuka dan kelas abstrak tetapi untuk sebagian besar kasus ini bertindak sama (Anda dapat membacanya di tautan di awal posting).
dWinder
Saya pikir dalam logika saya masih perlu menambahkan ini dengan benar? lain jika ($ this-> mapToProcess ['LIN'] ['LIN04'] == 'VN') $ this-> mapToProcess ['LIN'] ['LIN05'] = 'processSku';
Singleton
1
Anda harus menambahkan itu juga. Saya hanya menempatkan beberapa di antaranya sebagai contoh di mana logika seharusnya. Saya akan mengedit dengan itu juga untuk membuat kode menutupinya
dWinder
5

Anda tidak bisa menambahkan pernyataan if-else di dalam definisi konstan. Yang paling dekat dengan apa yang Anda cari mungkin adalah ini:

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

Akan menghasilkan:

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

Dengan kata lain, Anda perlu memecah array Anda menjadi konstanta yang terpisah, kemudian melakukan semua definisi kondisional, kemudian membangun array MAPPING akhir dari nilai konstan yang dihasilkan.

Karolis
sumber