PHP / Laravel-从请求获取JSON输入,名称动态匹配

时间:2018-08-27 12:02:02

标签: php json laravel

我目前正在通过在应用程序中使用Laravel从外部应用程序获取数据。

我在控制器文件中创建了一个简单的webhook,例如:

public function webhook(Request $request)
{
        $document = new Document();

        $document->fill($request->all());

        //Insert (or update existing) data in our database.
        $document::updateOrCreate(
            ['booking_reference' => $document->booking_reference],
            $document->getAttributes()
        );

        return response()->json('OK');
}

现在我的问题是,我必须将此数据插入表中。为此,接收到的json对象应与我的表列的名称匹配。我可以在外部应用程序中设置json名称-但是,有时外部应用程序会在json名称中添加子元素。

例如,假设这是我的数据库:

id    |   booking_reference   | shipment_reference

我的JSON有这些:

"booking_reference"  : "32000"
"shipment_reference" : "TREXOOO"

然后将数据正确插入到我的数据库中。但是,如上所述,JSON对象有时可能看起来像这样:

"booking_reference_0"  : "32000"
"shipment_reference_5" : "TREX000"

在此示例中,由于JSON名称与我的表名称不匹配,因此不会更新我的表。

该怎么办,以便可以动态地将数据插入表中?数据将始终具有表名的前缀,例如booking_referencebooking_reference_{child}

更新

使用Erubiel的答案,我可以使这些列动态匹配名称。但是,我有一个基本的belongsTo关系设置,但是Erubiel的解决方案剥离了$ document对象,只添加了 mapped 列。

$document->creator()->associate(auth()->user());

在我的模型中:

public function creator()
{
    return $this->belongsTo(User::class, 'user_id', 'id');
}

但是我的JSON响应不包含任何user_idcreator信息:

{"booking_reference":"CDK10000","pickup_location":"Afhentingsadresse 100 2650","drop_off_location":"Leveringsadresse 200 1000","comments":"HaHA","shipment_referenec":"SBRY100000"}

如果在foreach循环之前我刚得到$document

{"user_id":1,"creator":{"id":1,"name":"Oliver","email":"oliver@example.com","created_at":"2018-08-27 10:58:10","updated_at":"2018-08-27 10:58:10"}}

最终解决方案和解决方案

使用Erubiel的答案,我只是对其进行了一些修改,以将新值存储在现有的JSON对象中:

foreach ($request->all() as $key => $value) {
     $newKey = preg_replace("/(_?\d+)+$/", '', $key); //this generates the name of column that you need
     $document->$newKey = $value;
 }

哪个像咒符一样工作-输出:

{"user_id":1,"booking_reference":"CDK10000","pickup_location":"Afhentingsadresse 100 2650","drop_off_location":"Leveringsadresse 200 1000","comments":"HaHA","shipment_referenec":"SBRY100000","creator":{"id":1,"name":"Oliver","email":"oliver@example.com","created_at":"2018-08-27 10:58:10","updated_at":"2018-08-27 10:58:10"}}

3 个答案:

答案 0 :(得分:1)

这应该按照注释中的建议进行预处理。

public function webhook(Request $request)
{

    $arrAux = array();
    foreach($request->all() as $key => $value){
        $newKey = preg_replace("/(_?\d+)+$/","",$key); //this generates the name of column that you need
        $arrAux[$newKey] = $value;
    }

    //Insert (or update existing) data in our database.
    Document::updateOrCreate(
        ['booking_reference' => $arrAux['booking_reference']],
        $arrAux
    );

    return response()->json('OK');
}

答案 1 :(得分:0)

您解决问题的方法似乎类似于体系结构/设计反模式(基于原始json数据插入)。那不是回答你的问题,只是我的意见。

解决您问题的最快方法似乎是一个接受$ jsonKey并将其转换/返回$ dbKey的类。

您当前的代码:

$document->fill($request->all());

新方法:

$input = $this->translator->fromInput($request->all());
$document->fill($input);

示例净化/翻译类:

class Translator {
    /**
     * @param array $input
     * @return array
     */
    public function fromInput(array $input): array
    {
        $translated = [];

        foreach ($input as $key => $value) {
            switch ($key){
                case 'a':
                case 'a_1':
                    $translated['a'] = $value;
                    break;
                case mb_strpos($key, 'b'):
                    $translated['b'] = $value;
                    break;
                default: $translated[$key] = $value;
            }
        }

        return $translated;
    }
}

答案 2 :(得分:0)

添加受保护的$fillable属性以及要批​​量分配给模型的可用字段列表:

protected $fillable = ['booking_reference','shipment_reference'];

然后在控制器中捕获不匹配字段错误

try {
    $document->update($request->input());
} catch (MassAssignmentException $e) {
    $data = $request->input();
    foreach ($data as &$field) {
       preg_match('~([a-zA-Z]+(_[a-zA-Z]+)+)~', $field, $match);
       $field = $match[1];
    }
    $document->update($data);
}