2017-01-15 5 views
0

私はLaravelベースのプロジェクトを開始していますが、別のモデルインスタンスを作成する際に問題が発生しています。要約すると、私は "企業" MySQLテーブルを参照する "Company"モデルクラスと、 "locations"テーブルを参照する "Location"モデルクラスを持っています。両方のテーブルは関連しています(会社は多くのロケーションを持ち、各ロケーションは会社に属します)。ここまでは順調ですね。Laravel 5.3で関連するモデルインスタンスを作成する際にエラーが発生しました

少なくとも1つの会社の存在をチェックする「ミドルウェア」メカニズムがあります。企業がない場合は、初めてシステムを実行していると仮定して、「会社の作成」コントローラ/アクションを表示しますユーザーが最初の会社を作成したことを示します。提出すると、同じ会社情報を使用して1つのロケーションレコードが作成されるので、最終的にはデータベースのロケーションレコードは、作成された会社レコードのIDを「company_id」にする必要があります。

私はこの問題に関連する既存のファイルとクラスを表示してみましょう:企業のテーブルを作成する

移行ファイル:場所のテーブルを作成する

<?php 

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

class CreateCompaniesTable extends Migration { 
    /** 
    * Run the migrations. 
    * 
    * @return void 
    */ 
    public function up() { 
     Schema::create('companies', function (Blueprint $table) { 
      $table->increments('id'); 
      $table->string('nit'); 
      $table->string('name'); 
      $table->string('contact_name')->nullable(); 
      $table->string('address')->nullable(); 
      $table->string('phone')->nullable(); 
      $table->string('email')->nullable(); 
      $table->string('website')->nullable(); 
      $table->timestamps(); 
      $table->softDeletes(); 
      $table->integer('created_by')->unsigned()->nullable(); 
      $table->integer('updated_by')->unsigned()->nullable(); 
      $table->integer('deleted_by')->unsigned()->nullable(); 

      $table->foreign('created_by')->references('id')->on('users') 
       ->onDelete('cascade'); 
      $table->foreign('updated_by')->references('id')->on('users') 
       ->onDelete('cascade'); 
      $table->foreign('deleted_by')->references('id')->on('users') 
       ->onDelete('cascade'); 

      $table->index('nit'); 
      $table->index('name'); 
      $table->index('created_at'); 
      $table->index('deleted_at'); 
     }); 
    } 

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

移行ファイル:

<?php 

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

class CreateLocationsTable extends Migration { 
    /** 
    * Run the migrations. 
    * 
    * @return void 
    */ 
    public function up() { 
     Schema::create('locations', function (Blueprint $table) { 
      $table->increments('id'); 
      $table->integer('company_id')->unsigned()->nullable(); 
      $table->string('nit'); 
      $table->string('name'); 
      $table->string('contact_name')->nullable(); 
      $table->string('address')->nullable(); 
      $table->string('phone')->nullable(); 
      $table->string('email')->nullable(); 
      $table->string('website')->nullable(); 
      $table->timestamps(); 
      $table->softDeletes(); 
      $table->integer('created_by')->unsigned()->nullable(); 
      $table->integer('updated_by')->unsigned()->nullable(); 
      $table->integer('deleted_by')->unsigned()->nullable(); 

      $table->foreign('created_by')->references('id')->on('users') 
       ->onDelete('cascade'); 
      $table->foreign('updated_by')->references('id')->on('users') 
       ->onDelete('cascade'); 
      $table->foreign('deleted_by')->references('id')->on('users') 
       ->onDelete('cascade'); 

      $table->foreign('company_id')->references('id')->on('companies') 
       ->onDelete('cascade'); 

      $table->index('nit'); 
      $table->index('name'); 
      $table->index('created_at'); 
      $table->index('deleted_at'); 
     }); 
    } 

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

会社のモデルクラス

<?php 

namespace App; 

use Illuminate\Database\Eloquent\Model; 
use Illuminate\Database\Eloquent\SoftDeletes; 

/** 
* App\Company 
*/ 
class Company extends Model { 
    use SoftDeletes; 

    /** 
    * The attributes that are mass assignable. 
    * 
    * @var array 
    */ 
    protected $fillable = [ 
     'nit', 'name', 'contact_name', 'address', 'phone', 'email', 'website', 
    ]; 

    /** 
    * The attributes that should be mutated to dates. 
    * 
    * @var array 
    */ 
    protected $dates = ['deleted_at']; 

    /** 
    * Get the users for the company. 
    */ 
    public function users() { 
     return $this->hasMany(User::class); 
    } 

    /** 
    * Get the locations for the company. 
    */ 
    public function locations() { 
     return $this->hasMany(Location::class); 
    } 

    /** 
    * Get the invoices for the company. 
    */ 
    public function invoices() { 
     return $this->hasMany(Invoice::class); 
    } 

    /** 
    * Get the user that created the record. 
    */ 
    public function createdBy() { 
     return $this->belongsTo(User::class, 'created_by'); 
    } 

    /** 
    * Get the last user that updated the record. 
    */ 
    public function updatedBy() { 
     return $this->belongsTo(User::class, 'updated_by'); 
    } 

    /** 
    * Get the user that removed the record. 
    */ 
    public function deletedBy() { 
     return $this->belongsTo(User::class, 'deleted_by'); 
    } 

    /** 
    * Scope a query to only include the first active company. 
    * 
    * @param \Illuminate\Database\Eloquent\Builder $query 
    * @return \Illuminate\Database\Eloquent\Builder 
    */ 
    public function active($query) { 
     return $query->orderBy('id')->limit(1); 
    } 
} 

場所のモデルクラス:

<?php 

namespace App; 

use Illuminate\Database\Eloquent\Model; 
use Illuminate\Database\Eloquent\SoftDeletes; 

/** 
* App\Location 
*/ 
class Location extends Model { 
    use SoftDeletes; 

    /** 
    * The attributes that are mass assignable. 
    * 
    * @var array 
    */ 
    protected $fillable = [ 
     'nit', 'name', 'contact_name', 'address', 'phone', 'email', 'website', 'company_id', 
    ]; 

    /** 
    * The attributes that should be mutated to dates. 
    * 
    * @var array 
    */ 
    protected $dates = ['deleted_at']; 

    /** 
    * Get the company that owns the location. 
    */ 
    public function company() { 
     return $this->belongsTo(Company::class); 
    } 

    /** 
    * Get the products for the location. 
    */ 
    public function products() { 
     return $this->hasMany(Product::class); 
    } 

    /** 
    * Get the inventory records for the location. 
    */ 
    public function inventories() { 
     return $this->hasMany(Inventory::class); 
    } 

    /** 
    * Get the user that created the record. 
    */ 
    public function createdBy() { 
     return $this->belongsTo(User::class, 'created_by'); 
    } 

    /** 
    * Get the last user that updated the record. 
    */ 
    public function updatedBy() { 
     return $this->belongsTo(User::class, 'updated_by'); 
    } 

    /** 
    * Get the user that removed the record. 
    */ 
    public function deletedBy() { 
     return $this->belongsTo(User::class, 'deleted_by'); 
    } 
} 

言及したミドルウェアはシステムの最初の実行を検出する:

<?php 

namespace App\Http\Middleware; 

use App\Company; 
use Closure; 

class CheckSystemFirstRun { 
    /** 
    * Handle an incoming request. 
    * 
    * @param \Illuminate\Http\Request $request 
    * @param \Closure     $next 
    * @return mixed 
    */ 
    public function handle($request, Closure $next) { 

     /** @var \Illuminate\Http\Response $response */ 
     $response = $next($request); 

     // The verification must be done AFTER the response has been generated, otherwise the request's route is 
     // unknown. 
     if ($request->route()->getName() != 'company.create') { 

      // Check if there are no active companies. 
      if (Company::count() == 0) { 
       return redirect(route('company.create')); 
      } 
     } else { 

      // Check if there are active companies. 
      if (Company::count() > 0) { 
       return redirect(route('dashboard')); 
      } 
     } 

     return $response; 
    } 
} 

CompanyControllerクラスこれにより、ユーザは最初の当社及び場所の記録:

<?php 

namespace App\Http\Controllers; 

use App\Company; 
use App\Http\Requests\AddCompanyRequest; 
use Illuminate\Http\Request; 

class CompanyController extends Controller { 


    /** 
    * Show the form for creating a new resource. 
    * 
    * @return \Illuminate\Http\Response 
    */ 
    public function create() { 
     return view('company.create'); 
    } 

    /** 
    * Store a newly created resource in storage. 
    * 
    * @param AddCompanyRequest $request 
    * @param Company   $company 
    * @return \Illuminate\Http\Response 
    */ 
    public function store(AddCompanyRequest $request, Company $company) { 
     $company->create($request->all()); 

     // If there are no locations, create one using the same data as the received to create the company. 
     if ($company->locations->count() == 0) { 
      $company->locations()->create($request->all()); 
     } 

     return redirect()->route('company.create'); 
    } 
} 

、当社作成の検証が含まれている指定されたRequestクラス:データベースは、ブランドの新しいだと私はシステムを実行すると

<?php 

namespace App\Http\Requests; 

use Illuminate\Foundation\Http\FormRequest; 

class AddCompanyRequest extends FormRequest { 
    /** 
    * Determine if the user is authorized to make this request. 
    * 
    * @return bool 
    */ 
    public function authorize() { 
     return true; 
    } 

    /** 
    * Get the validation rules that apply to the request. 
    * 
    * @return array 
    */ 
    public function rules() { 
     return [ 
      'nit'  => 'required|max:255', 
      'name' => 'required|max:255', 
      'email' => 'required|email|unique:companies|max:255', 
      'website' => 'url|max:255', 
     ]; 
    } 

} 

が、私はにリダイレクトしています"会社の作成"アクション。提出すると、新しいCompanyレコードが正常に作成されますが、予想されるロケーションレコードはCompanyレコードとの予想される関係なく作成されます(company_id外部キー列はNULLを保持します)。

Company record successfully created

Location record created without the expected company_id value

私はので、私は自分のコードが間違っているのかわからないのですthe recommendation from Laravel 5.3を次しています。

この質問が投稿される前に、私は場所テーブルのcompany_idフィールドが移行でnullableとして定義される必要があることがわかりました。それ以前はそうではありませんでしたが、Laravel/PHPは、 "company_id"フィールドをnullにすることはできないため、MySQLに完全性エラーを返しました。また、新しいレコードのcompany_idを定義するために使用されたパラメータをdd()しようとしましたが、id値を返す関数は常にnullを返しました。また、私が試してみました:

$company->locations()->create($request->all()); 

$location = new Location($request->all()); 
$company->locations()->save($location); 

の両方を成功せず。

私は、Windows 10 x64、PHP 7.0.4上でWin32(AMD64)用のMySQLバージョン15.1 Distrib 10.1.10-MariaDBを使用しています。

ご協力いただきまして誠にありがとうございます。ありがとう。


更新ここ

01でアクションが実行されて実行されたクエリの出力:

---------------------- 
Query: insert into `companies` (`nit`, `name`, `contact_name`, `address`, `phone`, `email`, `website`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?, ?, ?, ?) 
Bindings: array (
    0 => '1113332323-9', 
    1 => 'TEST COMPANY INC', 
    2 => 'JOHN DOE', 
    3 => '1362 36TH PL', 
    4 => '8889990099', 
    5 => '[email protected]', 
    6 => 'http://test.com', 
    7 => '2017-01-16 00:16:25', 
    8 => '2017-01-16 00:16:25', 
) 
Time: 4.5099999999999998 

---------------------- 
Query: select * from `locations` where `locations`.`company_id` is null and `locations`.`company_id` is not null and `locations`.`deleted_at` is null 
Bindings: array (
) 
Time: 0.48999999999999999 

---------------------- 
Query: insert into `locations` (`nit`, `name`, `contact_name`, `address`, `phone`, `email`, `website`, `company_id`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
Bindings: array (
    0 => '1113332323-9', 
    1 => 'TEST COMPANY INC', 
    2 => 'JOHN DOE', 
    3 => '1362 36TH PL', 
    4 => '8889990099', 
    5 => '[email protected]', 
    6 => 'http://test.com', 
    7 => NULL, 
    8 => '2017-01-16 00:16:25', 
    9 => '2017-01-16 00:16:25', 
) 
Time: 4.5300000000000002 
+0

する必要があり、場所の作成コードは(私がローカルで最小限の例を作成し、 'company_id'が正しく割り当てられている)右に見えます。クエリログを確認して結果を投稿できますか? – nCrazed

+0

また、 '$ company :: locations() - > create([])'が正しいfk値を割り当てるべきであるため、FKカラムをヌル可能にする必要はありません。 – nCrazed

+0

@ nCrazed、主な質問内容の「更新01」セクションを確認してください。私は、要求されたログ出力を追加しました。挿入クエリにcompany_id値がありません。ヌル可能なcompany_idに関するあなたのコメントについては、私はあなたに同意します。移行ファイルからnull許容フラグを削除して更新すると、必要なcompany_idなしでロケーションレコードが挿入されているため、前述のプロセスで整合性違反例外が生成されます。 –

答えて

1

あなたがいない上CompanyのあなたのORMインスタンスに場所を追加します新しく作成されたレコード。

$company->create($request->all()); 

は別に、いくつかの無関係な改善から

$company = $company->create($request->all()); 
+0

それは答えです。私は作成/保存メソッドは、同じ$会社の変数に結果を割り当てる必要なく、同じ$会社のインスタンスを更新します。どうもありがとう。 –

関連する問題