How to dynamically build this query - Laravel/Lumen

主宰稳场 提交于 2020-02-25 05:42:48

问题


I have the following input from the user:

array (
  'id_coretable' => 1,
  'Internal_key' => 'UPDATED1',
  'extensiontable_itc' => 
  array (
    'description_itc' => 'UPDATED1',
  ),
  'extensiontable_sysops' => 
  array (
    'description_sysops' => 'UPDATED1',
  ),
)  

and its contents shall update the following model:

array (
  'id_coretable' => 1,
  'Internal_key' => 'TESTKEY_1',
  'extensiontable_itc' => 
  array (
    'description_itc' => 'EXTENSION_ITC_1',
  ),
  'extensiontable_sysops' => 
  array (
    'description_sysops' => 'EXTENSION_SYSOPS_1',
  ),
)  

This model was created with this code:

$joinAsArray = coretable::with($permittedTables)->find(1);

Where $permittedTables is an array of tablenames which determine the tables to be joined with coretable.

Now, I've spent multiple hours on pondering how to properly loop over a model, and it simply isnt possible without serializing the model to a plain array or the like. This doesnt really help though, since I want to UPDATE the model here, and if I just convert it to an array, then I lose this connection to the DB/Model.

So I'm now using a different approach. I'm looping the userinput, which will ALWAYS have the same structure and indexes as the model. And then I'm using the keys from the very well loopable userinputarray and a copy of the old model in form of an array, to determine the attributes of the model which shall be updated with the respective input data. This is what my code currently looks like:

foreach($input as $key => $value){
  foreach($modelAsArray as $keyOld => $valueOld){ 

  //$keyOld is ALWAYS the same key as the "new" one. 
  //$keyOld was only chosen to both distinguish from the outer loops $key and to 
  //maintain its relationship to $valueOld, which is indeed the old value! ;)

    coretable::with($permittedTables)->where($key, $valueOld)->update([$key => $value]);
  }
}

Now, this code works pretty neatly for the outer array. I can indeed update the "Internal_key" field this way. However, once we hit the point where the joined table is represented in form of the "nested array", things go south. I get the following error message:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'extensiontable_itc' in 'where clause' (SQL: update `coretable` set `extensiontable_itc` = {"description_itc":"UPDATED1"}, `coretable`.`updated_at` = 2020-02-06 16:07:06 where `extensiontable_itc` = UPDATED1)

I can kind of see where this comes from. Its trying to find a column extensiontable_itc on coretable which obviously isnt there since it is its own relation, only connected to the coretable via FK.

The first thing that comes to my mind to deal with this problem is calling another model by dynamically inserting its name via the $key. Then I would have to loop over the nested arrays keys and values, basically doing the same thing as I did with the outer array.

This probably will consume a comparatively horrible amount of ressources, but this software is for internal purposes only and our DB-server probably will be able to handle this load. Its also quite hacky, I think^^

So, can anyone else give me another, more elegant, less ressource hungry and less hacky solution than mine?

EDIT: As per request in the comments, here are my migrations:

Coretable

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCoretable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('coretable', function (Blueprint $table) {
            $table->bigIncrements('id_coretable');
            $table->string('Internal_key')->nullable(false)->unique();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('coretable');
    }
}

extensiontable_itc

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateExtensiontableItc extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('extensiontable_itc', function (Blueprint $table) {
            $table->bigIncrements('id_extensiontable_itc');
            $table->bigInteger('coretable_id')->unsigned()->unique()->nullable(false);
            $table->foreign('coretable_id', 'fk_extensiontable_itc_coretable')->references('id_coretable')->on('coretable');
            $table->string('description_itc')->nullable(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('extensiontable_itc');
    }
}

extensiontable_sysops

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ExtensiontableSysops extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('extensiontable_sysops', function (Blueprint $table) {
            $table->bigIncrements('id_extensiontable_sysops');
            $table->bigInteger('coretable_id')->unsigned()->nullable(false)->unique();
            $table->foreign('coretable_id', 'fk_extensiontable_sysops_coretable')->references('id_coretable')->on('coretable');
            $table->string('description_sysops')->nullable(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('extensiontable_sysops');
    }
}

回答1:


SQLSTATE[42S22]: Column not found: 1054 Unknown column 'extensiontable_itc' in 'where clause' (SQL: update coretable set extensiontable_itc = {"description_itc":"UPDATED1"}, coretable.updated_at = 2020-02-06 16:07:06 where extensiontable_itc = UPDATED1)

You can't update relation data via with('relation')->update().

I will make an example to implement this, based on your migration files.


Core

namespace App;

use App\ExtensiontableItc;
use App\ExtensiontableSysops;
use Illuminate\Database\Eloquent\Model;

class Core extends Model
{
    protected $table      = 'coretable';
    protected $primaryKey = 'id_coretable';
    protected $fillable   = [
        'id_coretable',
        'Internal_key',
    ];

    public function extensiontable_itc()
    {
        return $this->hasOne(ExtensiontableItc::class, 'coretable_id', 'id_coretable');
    }

    public function extensiontable_sysops()
    {
        return $this->hasOne(ExtensiontableSysops::class, 'coretable_id', 'id_coretable');
    }
}

ExtensiontableItc

namespace App;

use Illuminate\Database\Eloquent\Model;

class ExtensiontableItc extends Model
{
    protected $table      = 'extensiontable_itc';
    protected $primaryKey = 'id_extensiontable_itc';
    protected $fillable   = [
        'coretable_id',
        'description_itc',
    ];
}

ExtensiontableSysops

namespace App;

use Illuminate\Database\Eloquent\Model;

class ExtensiontableSysops extends Model
{
    protected $table      = 'extensiontable_sysops';
    protected $primaryKey = 'id_extensiontable_sysops';
    protected $fillable   = [
        'coretable_id',
        'description_sysops',
    ];
}

Usage

$permittedTables = ['extensiontable_itc', 'extensiontable_sysops'];
$core            = Core::with($permittedTables)->find(1);

You will get (based on your example)

array:6 [
  "id_coretable" => 1
  "Internal_key" => "TESTKEY_1"
  "created_at" => "2020-02-07 18:05:50"
  "updated_at" => "2020-02-07 18:05:50"
  "extensiontable_itc" => array:5 [
    "id_extensiontable_itc" => 1
    "coretable_id" => 1
    "description_itc" => "UPDATED1"
    "created_at" => "2020-02-07 18:17:08"
    "updated_at" => "2020-02-07 11:32:44"
  ]
  "extensiontable_sysops" => array:5 [
    "id_extensiontable_sysops" => 1
    "coretable_id" => 1
    "description_sysops" => "UPDATED1"
    "created_at" => "2020-02-07 18:17:21"
    "updated_at" => "2020-02-07 11:32:44"
  ]
]

To update your relation, you need to call extensiontable_itc and extensiontable_sysops eager load via Core model.


$input = [
    'id_coretable'          => 1,
    'Internal_key'          => 'TESTKEY_1',
    'extensiontable_itc'    => [
        'description_itc' => 'EXTENSION_ITC_1',
    ],
    'extensiontable_sysops' => [
        'description_sysops' => 'EXTENSION_SYSOPS_1',
    ],
];

$permittedTables = ['extensiontable_itc', 'extensiontable_sysops'];
$core            = Core::with($permittedTables)->find(1);

// Update extensiontable_itc
$core->extensiontable_itc->update($input['extensiontable_itc']);

// Update extensiontable_sysops
$core->extensiontable_sysops->update($input['extensiontable_sysops']);


来源:https://stackoverflow.com/questions/60099351/how-to-dynamically-build-this-query-laravel-lumen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!