매핑 배열에 같은 이름의 새 segmentId를 추가하고 싶지만 다른 elementId이지만 동일한 메소드를 사용하고 싶습니다.


14

아래는 MapperInterface.php입니다

const에 if-else 문을 추가하는 방법을 알아 내려고합니다. 매핑 배열. 다음과 같은 것 :

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

나는 그것이 의미가 있기를 바랍니다. 더 좋은 방법이 있는지 확실하지 않지만 궁극적으로 하나 이상의 "LIN"segmentId가 필요합니다. 아마도 새로운 기능을 추가 하고이 조건을 사용합니까?

새로운 파일 답변 ***

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

}

그래서 MAPPING const 배열을 동적으로 만들고 싶습니까? const로는 그렇게 할 수 없습니다. 다른 함수를 사용하여 해당 배열을 가져
와서

나는 당신이 무엇을하려고하는지 모르겠습니다. 무엇을 달성하고 싶습니까?
Stephan Vierkant

답변:


6

당신이 볼 수 있듯이 여기 - const를 변수는 변경 또는 보류 논리가 될 수 없습니다 . 인터페이스는 논리도 보유 할 수 없으므로 인터페이스에서 논리를 수행 할 수 없습니다.

귀하의 문제에 대한 더 나은 해결책은 추상 클래스 를 사용하는 것 입니다. 나는 당신의 인터페이스와 동일 할 것입니다 ( 여기 에서 다른 것에 대한 토론을 볼 수 있지만 귀하의 필요에 대해 동일하다고 생각합니다).

다음과 같이 추상 클래스를 만드는 것이 좋습니다.

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

}

이제 다음과 같이 상속 된 객체를 선언 할 수 있습니다.

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

사용 예는 다음과 같습니다.

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

논리가 변경되지 않는 것 같으므로 새 변수를 넣고 구성 중에 설정했습니다. 원하는 경우 덤프하고 getProcess함수 의 반환 값을 수정하면 모든 논리를 거기에 넣습니다.

또 다른 옵션은 $mapToProcess대중 을 만들고 직접 액세스하는 것이지만 더 나은 프로그래밍은 getter 메소드를 사용하는 것입니다.

희망이 도움이됩니다!


마지막 추상 함수 public function map (array $ segments) 바로 아래의 동일한 파일에 전체 추상 클래스를 통합 / 추가 할 수 있어야합니다. OrderUpdateInterface; } 여기
Singleton

이제 이전 코드를 모두 재정의 하고이 추상 클래스를 사용할 수 있습니까? 나는 대답을 정확하고 친구에게 매우 도움이되었다고 표시했다. @dWinder
싱글턴

그래 넌 할수있어. 인터페이스와 추상 클래스에는 차이가 있지만 대부분의 경우 동일하게 작동합니다 (포스트 시작 부분의 링크에서 읽을 수 있음).
dWinder

나는 논리에서 여전히 이것을 올바르게 추가해야한다고 생각합니까? 그렇지 않으면 ($ this-> mapToProcess [ 'LIN'] [ 'LIN04'] == 'VN') $ this-> mapToProcess [ 'LIN'] [ 'LIN05'] = 'processSku';
싱글턴

1
당신도 그것을 추가해야합니다. 나는 논리의 위치에 대한 예로 단지 일부를 넣었습니다. 코드를 다루기 위해 편집 할 것입니다
dWinder

5

상수 정의 안에 if-else 문을 추가 할 수 없습니다. 당신이 찾고있는 것에 가장 가까운 것은 아마도 이것입니다 :

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

출력합니다 :

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

즉, 배열을 별도의 상수로 분리 한 다음 모든 조건부 정의를 수행 한 다음 결과 상수 값에서 최종 MAPPING 배열을 구성해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.