【问题标题】:BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::createTickets()BadMethodCallException:调用未定义的方法 Illuminate\Database\Query\Builder::createTickets()
【发布时间】:2019-12-12 14:17:56
【问题描述】:

我正在开发 Order-Ticket 功能。理想情况下,应该为单个订单生成许多票。

之前,创建工单的职责写在 Order 模型中,那时它运行良好,但现在我试图将这个职责转移到 Ticket 模型本身,它不起作用。

我将从测试文件“TicketTest.php”开始

<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\Concert;
use Carbon\Carbon;
use App\Order;

class TicketTest extends TestCase
{
    use DatabaseMigrations;

    /** @test */
    function can_create_multiple_tickets_for_order(){

        $numberOfTickets = 2;

        // Arrange - Create Concert and Order
        $concert = factory(Concert::class)->create(
            [
                'date' => Carbon::parse('December 1, 2016 8:00pm'),
            ]
        );

        $order = $concert->orders()->create([
            'email' => 'abc@gmail.com'
        ]);

        // Act - Create Tickets
        $order->tickets()->createTickets($numberOfTickets); // This line throws call to undefined method.

        // Assert
        $this->assertEquals($numberOfTickets, $order->tickets()->count());

    }
}

'Order.php' 模型

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected $guarded = [];

    public function tickets()
    {
        return $this->hasMany(Ticket::class);
    }

}

'Ticket.php' 模型

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Ticket extends Model
{
    public function createTickets($ticketQuantity){
        foreach(range(1, $ticketQuantity) as $i) {
            $this->create([]);
        }
    }

    public function order(){
        return $this->belongsTo(Order::class);
    }
}

【问题讨论】:

    标签: laravel-5


    【解决方案1】:

    在 Laravel 5.4 之前,我通过创建一个新的关系并将该关系映射到 OrderTicket 来解决这个问题。创建了一个文件“app/Relation/TicketOrderRelation.php”并在其中添加了以下代码

    <?php
    namespace App\Relation;
    
    use Illuminate\Database\Eloquent\Relations\HasMany;
    
    class TicketOrderRelation extends HasMany {
    
        /**
         * Create a Collection of new tickets
         *
         * @param int $ticketQuantity Number of Tickets to be created 
         * @return \Illuminate\Database\Eloquent\Collection
         */
        public function createTickets($ticketQuantity){
            $instances = [];
    
            foreach(range(1, $ticketQuantity) as $i) {
                $instances[] = $this->create([]);
            }
    
            return collect($instances);
        }
    }
    

    新的“Order.php”文件

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    use App\Relation\TicketOrderRelation;
    
    class Order extends Model
    {
        protected $guarded = [];
    
        /**
         * Define a one-to-many relationship. One Order can have many tickets.
         * 
         * This method is duplicate of hasMany method. The only difference is it
         * returns object of TicketOrderRelation class at the bottom instead of 
         * object of HasMany class.
         *
         * @param  string  $related
         * @param  string  $foreignKey
         * @param  string  $localKey
         * @return \App\Relation\TicketOrderRelation
         */
        public function ticketOrderRelation($related, $foreignKey = null, $localKey = null)
        {
            $foreignKey = $foreignKey ?: $this->getForeignKey();
    
            $instance = new $related;
    
            $localKey = $localKey ?: $this->getKeyName();
    
            return new TicketOrderRelation($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
        }
    
        public function tickets()
        {
            return $this->ticketOrderRelation(Ticket::class);
        }
    
    }
    

    新的“Ticket.php”文件

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Ticket extends Model
    {
    
        protected $guarded = [];
    
        public function order()
        {
            return $this->belongsTo(Order::class);
        }
    }
    

    在 Laravel 5.4 之后,Eloquent builder 开始支持 create 方法,这使得创建变得容易。

    This 答案显示了如何创建自定义生成器。我还没有尝试自定义构建器是否在 Laravel 5.4 上解决了这个问题,但如果可以,那么我更愿意这样做。

    【讨论】:

      猜你喜欢
      • 2017-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 2014-04-23
      相关资源
      最近更新 更多