Eloquent Builder实例不存在[method]属性问题求助
[method]属性错误 错误详情
Property [method] does not exist on the Eloquent builder instance.
Builder->__get('method')
in core/app/Http/Controllers/Provider/PaymentController.php (line 210)
问题场景
将Gateway/PaymentController.php与Models/GatewayCurrency.php的代码复制到Provider/PaymentController.php和Models/ProviderCurrency.php后,Gateway站点运行正常,但Provider站点触发上述错误,错误位于core/app/Http/Controllers/Provider/PaymentController.php第210行。
相关代码
PaymentController.php
<?php namespace App\Http\Controllers\Provider; use App\Http\Controllers\Controller; use App\Lib\FormProcessor; use App\Models\AdminNotification; use App\Models\Agent; use App\Models\Currency; use App\Models\Transfer; use App\Models\ProviderCurrency; use App\Models\Transaction; use App\Models\User; use App\Models\Wallet; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class PaymentController extends Controller{ public function transfer(){ $pageTitle = 'Payment Methods'; return view($this->activeTemplate . providerView('transfer'), compact('pageTitle')); } public function transferInsert(Request $request){ $request->validate([ 'amount' => 'required|numeric|gt:0', 'provider_id' => 'required', 'currency' => 'required', ]); $user = userGuard()['user']; $currency = Currency::enable()->find($request->currency_id); if(!$currency) { $notify[] = ['error', 'Invalid currency']; return back()->withNotify($notify); } $gate = ProviderCurrency::whereHas('method', function ($gate) { $gate->where('status', 1); })->where('provider_id', $request->provider_id)->where('currency', $request->currency)->first(); if (!$gate) { $notify[] = ['error', 'Invalid provider']; return back()->withNotify($notify); } if ($gate->min_amount / $currency->rate > $request->amount || $gate->max_amount / $currency->rate < $request->amount) { $notify[] = ['error', 'Please follow transfer limit']; return back()->withNotify($notify); } $charge = $gate->fixed_charge + ($request->amount * $gate->percent_charge / 100); $payable = $request->amount + $charge; $final_amo = $payable; $data = new Transfer(); $data->user_id = $user->id; $data->user_type = userGuard()['type']; $data->wallet_id = $request->wallet_id; $data->currency_id = $request->currency_id; $data->provider_id = $gate->provider_id; $data->method_currency = strtoupper($gate->currency); $data->amount = $request->amount; $data->charge = $charge; $data->rate = 1; $data->final_amo = $final_amo; $data->trx = getTrx(); $data->save(); session()->put('Track', $data->trx); return to_route(strtolower(userGuard()['type']).'.transfer.confirm'); } public function appTransferConfirm($hash) { try { $id = decrypt($hash); } catch (\Exception $ex) { return "Sorry, invalid URL."; } $data = Transfer::where('id', $id)->where('status', 0)->orderBy('id', 'DESC')->firstOrFail(); if($data->user_type == 'USER'){ $user = User::findOrFail($data->user_id); Auth::login($user); logoutAnother('user'); } elseif($data->user_type == 'AGENT'){ $user = Agent::findOrFail($data->user_id); Auth::guard('agent')->login($user); logoutAnother('agent'); } session()->put('Track', $data->trx); return to_route(strtolower(userGuard()['type']).'.transfer.confirm'); } public function transferConfirm() { $track = session()->get('Track'); $transfer = Transfer::where('trx', $track)->where('status',0)->orderBy('id', 'DESC')->with('provider')->firstOrFail(); if ($transfer->provider_id >= 1000) { return to_route(strtolower(userGuard()['type']).'.transfer.manual.confirm'); } $dirName = $transfer->provider->alias; $new = __NAMESPACE__ . '\\' . $dirName . '\\ProcessController'; $data = $new::process($transfer); $data = json_decode($data); if (isset($data->error)) { $notify[] = ['error', $data->message]; return to_route(providerRedirectUrl())->withNotify($notify); } if (isset($data->redirect)) { return redirect($data->redirect_url); } // for Stripe V3 if(@$data->session){ $transfer->btc_wallet = $data->session->id; $transfer->save(); } $pageTitle = 'Payment Confirm'; return view($this->activeTemplate . $data->view, compact('data', 'pageTitle', 'transfer')); } public static function userDataUpdate($transfer,$isManual = null) { if ($transfer->status == 0 || $transfer->status == 2) { $transfer->status = 1; $transfer->save(); if($transfer->user_type == 'USER'){ $user = User::find($transfer->user_id); $userType = 'USER'; } elseif($transfer->user_type == 'AGENT'){ $user = Agent::find($transfer->user_id); $userType = 'AGENT'; } $userWallet = Wallet::find($transfer->wallet_id); $userWallet->balance += $transfer->amount; $userWallet->save(); $transaction = new Transaction(); $transaction->user_id = $user->id; $transaction->user_type = $transfer->user_type; $transaction->wallet_id = $userWallet->id; $transaction->currency_id = $transfer->currency_id; $transaction->before_charge = $transfer->amount; $transaction->amount = $transfer->amount; $transaction->post_balance = $userWallet->balance; $transaction->charge = 0; $transaction->trx_type = '+'; $transaction->details = 'Transfer money to ' . $transfer->providerCurrency()->name; $transaction->trx = $transfer->trx; $transaction->remark = 'transfer_money'; $transaction->save(); if (!$isManual) { $adminNotification = new AdminNotification(); $adminNotification->user_type = $userType; $adminNotification->user_id = $user->id; $adminNotification->title = 'Transfer successful to '.$transfer->providerCurrency()->name; $adminNotification->click_url = urlPath('admin.transfer.successful'); $adminNotification->save(); } notify($user, $isManual ? 'TRANSFER_APPROVE' : 'TRANSFER_COMPLETE', [ 'method_name' => $transfer->providerCurrency()->name, 'method_currency' => $transfer->method_currency, 'method_amount' => showAmount($transfer->final_amo, getCurrency($transfer->method_currency)), 'amount' => showAmount($transfer->amount, $transfer->currency), 'charge' => showAmount($transfer->charge, $transfer->currency), 'currency' => $transfer->currency->currency_code, 'rate' => showAmount($transfer->rate), 'trx' => $transfer->trx, 'post_balance' => showAmount($userWallet->balance, $transfer->currency) ]); } } public function manualTransferConfirm() { $track = session()->get('Track'); $data = Transfer::with('provider')->where('status', 0)->where('trx', $track)->first(); if (!$data) { return to_route(providerRedirectUrl()); } if ($data->provider_id > 999) { $pageTitle = 'Transfer Confirm'; $method = $data->providerCurrency(); $provider = $method->method; return view($this->activeTemplate . providerView('manual_confirmp',true), compact('data', 'pageTitle', 'method', 'provider')); } abort(404); } public function manualTransferUpdate(Request $request) { $track = session()->get('Track'); $data = Transfer::with('provider')->where('status', 0)->where('trx', $track)->first(); $userType = null; if($data->user_type == 'USER'){ $user = User::find($data->user_id); $userType = 'USER'; } elseif($data->user_type == 'AGENT'){ $user = Agent::find($data->user_id); $userType = 'AGENT'; } if (!$data) { return to_route(providerRedirectUrl()); } $providerCurrency = $data->providerCurrency(); $provider = $providerCurrency->method; $formData = $provider->form->form_data; $formProcessor = new FormProcessor(); $validationRule = $formProcessor->valueValidation($formData); $request->validate($validationRule); $userData = $formProcessor->processFormData($request, $formData); $data->detail = $userData; $data->status = 2; // pending $data->save(); $adminNotification = new AdminNotification(); $adminNotification->user_type = $userType; $adminNotification->user_id = $data->getUser->id; $adminNotification->title = 'Transfer money request from '.$user->username; $adminNotification->click_url = urlPath('admin.transfer.details',$data->id); $adminNotification->save(); notify($data->getUser, 'TRANSFER_REQUEST', [ 'method_name' => $data->providerCurrency()->name, 'method_currency' => $data->method_currency, 'method_amount' => showAmount($data->final_amo), getCurrency($data->method_currency), 'amount' => showAmount($data->amount, $data->convertedCurrency), 'charge' => showAmount($data->charge, $data->convertedCurrency), 'rate' => showAmount(1, $data->convertedCurrency), 'trx' => $data->trx, 'currency' => $data->convertedCurrency->currency_code, ]); $notify[] = ['success', 'You transfer money request has been taken']; return to_route(strtolower(userGuard()['type']).'.transfer.history')->withNotify($notify); } }
Models/ProviderCurrency.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class ProviderCurrency extends Model { protected $casts = ['status' => 'boolean']; // Relation public function method() { return $this->belongsTo(Provider::class, 'provider_id', 'code'); } public function currencyIdentifier() { return $this->name ?? $this->method->name . ' ' . $this->currency; } public function scopeBaseCurrency() { return $this->method->crypto == 1 ? 'USD' : $this->currency; } public function scopeBaseSymbol() { return $this->method->crypto == 1 ? '$' : $this->symbol; } }
问题原因
错误根源在ProviderCurrency模型的两个scope方法:scopeBaseCurrency和scopeBaseSymbol。
Laravel中,以scope开头的方法是查询作用域,这类方法的第一个参数是Eloquent Builder实例,而非模型实例。但当前代码直接在scope方法中使用$this->method,此时$this指向Builder对象,该对象不存在method属性,因此触发错误。
另外,这两个方法的用途是获取属性值,并非构建查询逻辑,完全不适合定义为scope方法。
解决方案
将这两个scope方法改为普通实例方法,去掉scope前缀,修改后的ProviderCurrency.php代码如下:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class ProviderCurrency extends Model { protected $casts = ['status' => 'boolean']; // Relation public function method() { return $this->belongsTo(Provider::class, 'provider_id', 'code'); } public function currencyIdentifier() { return $this->name ?? $this->method->name . ' ' . $this->currency; } public function baseCurrency() { return $this->method->crypto == 1 ? 'USD' : $this->currency; } public function baseSymbol() { return $this->method->crypto == 1 ? '$' : $this->symbol; } }
同时,检查代码中调用这两个方法的地方,将原来的查询链式调用(如ProviderCurrency::baseCurrency())改为实例调用(如$providerCurrency->baseCurrency()),确保在模型实例上调用这些方法。
内容的提问来源于stack exchange,提问作者Sam

