tighten / parental

Use single table inheritance in your Laravel app
MIT License
1.36k stars 98 forks source link

Column reference is ambiguous #50

Closed gitkv closed 5 years ago

gitkv commented 5 years ago

Hi, I have the following problem.

I have 2 models: InvoiceItem - parent

<?php

namespace App\Models;

use App\Enums\ProductType;
use Illuminate\Database\Eloquent\Model;
use \Tightenco\Parental\HasChildren;

class InvoiceItem extends Model {

    use HasChildren;

    protected $table = 'invoice_items';

    //...

    protected $childColumn = 'product_type';

    protected $childTypes = [
        ProductType::SUBSCRIBE => InvoiceItemSubscribe::class,
    ];
    //...

InvoiceItemSubscribe - children, have scopeForAct method

<?php

namespace App\Models;

use Carbon\Carbon;
use Tightenco\Parental\HasParent;

class InvoiceItemSubscribe extends InvoiceItem {

    use HasParent;

    //...

    /**
     * @param $query
     * @param Carbon $prevMonth
     */
    public function scopeForAct($query, Carbon $prevMonth) {
        $query
            ->select('invoice_items.*')
            ->whereDate('invoice_items.date_from', '<', $prevMonth)
            ->leftJoin('act_items', 'invoice_items.id', '=', 'act_items.invoice_item_id')
            ->groupBy('invoice_items.id')
            ->havingRaw('ceil(invoice_items.amount) > count(act_items.id)')
            ->whereHas('invoice', function ($query) {
                $query->paid();
            });
    }
}

I execute the query:

App\Models\InvoiceItemSubscribe::forAct($date)->get();

query to sql:

select "invoice_items".*
     from "invoice_items"
              left join "act_items" on "invoice_items"."id" = "act_items"."invoice_item_id"
     where "invoice_items"."date_from"::date < '2019-07-09 00:00:00'
       and exists(select *
                  from "invoices"
                  where "invoice_items"."invoice_id" = "invoices"."id"
                    and "invoice_status" = 'paid')
       and "product_type" = 'subscribe'
     group by "invoice_items"."id"
     having ceil(invoice_items.amount) > count(act_items.id)

Postgress return: [2019-07-09 11:07:34] [42702] ERROR: column reference "product_type" is ambiguous

I wanted to fix this by adding a prefix to the table name in the $childColumn variable

protected $childColumn = 'invoice_items.product_type';

This of course solves the ambiguity problem. But with this fix, your package stops working, when all records are requested by the parent model, instances of the parent model are returned, but the children are expected.

App\Models\InvoiceItem::all();

I expect instance

App\Models\InvoiceItemSubscribe::class

I get instance

App\Models\InvoiceItem::class
gitkv commented 5 years ago

The solution to this problem: In the file src/HasParent.php on line 26 add concatenation with the name of the table.

$query->where($instance->getTable().'.'.$instance->getInheritanceColumn(), $instance->classToAlias(get_class($instance)));
<?php
trait HasParent
{

    //...
    public static function bootHasParent()
    {
        //...

        static::addGlobalScope(function ($query) {
            $instance = new static;

            if ($instance->parentHasHasChildrenTrait()) {
                $query->where($instance->getTable().'.'.$instance->getInheritanceColumn(), $instance->classToAlias(get_class($instance)));
            }
        });
    }

    //...
}
dallincoons commented 5 years ago

Do you mind submitting a PR?

gitkv commented 5 years ago

I'm not against. But now you need to solve a lot of current problems. I will do as liberation.

gitkv commented 5 years ago

I created PR #51

calebporzio commented 5 years ago

Thanks for the PR - merged and tagged: v0.7.1