我剛剛開始使用基於Laravel的項目,並且在創建與另一個模型實例相關的模型實例時遇到問題。總之,我有一個「公司」模型類,它引用「公司」MySQL表,還有一個引用「位置」表的「位置」模型類。兩個表格都是相關的(公司有許多地點,每個地點都屬於公司)。到現在爲止還挺好。在Laravel 5.3中創建相關模型實例時出錯
我有一個「中間件」機制檢查是否存在至少一家公司,如果沒有公司,我假設這是第一次運行系統,所以我顯示「創建公司」控制器/操作用戶創建第一家公司。在提交時,這也會創建一個使用相同公司信息的單個位置記錄,因此最終數據庫中的位置記錄應該將「company_id」作爲剛剛創建的公司記錄的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');
}
}
也包含了公司創建驗證指定的請求類:
<?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_id外鍵列保持NULL)的預期關係的情況下創建的。
我下面the recommendation from Laravel 5.3所以我不知道什麼是錯我的代碼。
在發佈此問題之前,我發現locations表中的company_id字段可能需要在遷移中定義爲可空;它之前不是這樣,但是當時Laravel/PHP迴應了MySQL的完整性錯誤,因爲「company_id」字段不能爲空。我也嘗試dd()用於在新記錄上定義company_id的參數,但返回id值的函數總是返回null。另外,我曾嘗試:
$company->locations()->create($request->all());
和
$location = new Location($request->all());
$company->locations()->save($location);
都沒有成功。
我正在使用MySQL Ver 15.1 Distrib 10.1.10-MariaDB,用於Windows 10 x64,PHP 7.0.4上的Win32(AMD64)。
任何幫助,高度讚賞。謝謝。
更新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
除了一些不相關的改進,位置創建代碼看起來正確(我創建了一個小例子,在本地和'company_id'正確分配)。你可以檢查你的查詢日誌併發布結果嗎? – nCrazed
另外,您應該不需要將FK列設置爲空(除非您有沒有公司的位置的用例),因爲'company :: locations() - > create([])'應該指定正確的fk值。 – nCrazed
@ nCrazed,請查看主要問題內容中的「更新01」部分。我只是按要求添加了日誌輸出。插入查詢缺少company_id值。至於你對可空的company_id的評論,我同意你的看法。如果我從遷移文件中刪除可空標誌並進行刷新,則上述過程將生成完整性違例異常,因爲位置記錄插入時沒有所需的company_id。 –