我想将一个新的 segmentId(同名)添加到我的映射数组中,但使用不同的 elementId 但相同的方法

I want to add a new segmentId (with the same name) into my mapping array but with a different elementId but same method

提问人:Singleton 提问时间:1/14/2020 最后编辑:Singleton 更新时间:1/23/2020 访问量:310

问:

下面是MapperInterface.php

我正在尝试弄清楚如何将 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;
}

我希望这是有道理的。不确定是否有更好的方法可以解决这个问题,但最终我需要超过 1 个“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()];
    }

}
PHP 数组映射 常量

评论

0赞 dWinder 1/16/2020
所以你希望 MAPPING const 数组是动态的?你不能用 const 做到这一点。您可以使用另一个函数来获取该数组,并在需要时进行修改
0赞 Stephan Vierkant 1/16/2020
我真的不知道你想做什么。你想达到什么目的?

答:

6赞 dWinder 1/16/2020 #1

正如你在这里看到的 - const 变量不能是 change 或 hold 逻辑。 请注意,接口也不能保存逻辑 - 因此您不能在接口中执行此操作。

我认为解决您的问题的更好方法是使用抽象类。我将与您的界面相同(您可以在此处看到有关不同的讨论,但我认为它对您的需求也是一样的)。

我建议创建抽象类,如下所示:

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

另一种选择是公开并直接访问它,但我想更好的编程是使用 getter 方法。$mapToProcess

希望对您有所帮助!

评论

0赞 Singleton 1/17/2020
我应该能够将整个抽象类集成/添加到我的同一文件中,就在最后一个函数公共函数映射(数组$segments)的下方:OrderUpdateInterface;} 这里
0赞 Singleton 1/17/2020
所以现在我可以覆盖所有旧代码并使用这个抽象类吗?我把答案标记为正确,对我的朋友很有帮助。@dWinder
0赞 dWinder 1/17/2020
是的你可以。接口和抽象类之间是有区别的,但在大多数情况下,它的作用是一样的(你可以在文章开头的链接中阅读它)。
0赞 Singleton 1/22/2020
我认为在逻辑中我仍然需要添加这个,对吗?else if ($this->mapToProcess['LIN']['LIN04'] == 'VN') $this->mapToProcess['LIN']['LIN05'] = 'processSku';
1赞 dWinder 1/22/2020
你也应该添加它。我只举了其中的一些作为逻辑应该在哪里的例子。我也会用它来编辑,使代码覆盖它
5赞 Karolis 1/16/2020 #2

不能在常量定义中添加 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 数组。