Skip to content

[Laravel] BelongsTo Link is not working #6930

Closed
@llei4

Description

@llei4

API Platform version(s) affected: 4.0.16

Description
When creating a SubResource for a HasMany Realation on a Model Link Fails.
How to reproduce

Possible Solution
Having 2 Models:

GrandFather

<?php

namespace App\Models;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Link;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

#[ApiResource()]
#[ApiResource(
    uriTemplate: '/grand_sons/{id_grand_son}/grand_father',
    uriVariables: [
        'id_grand_son' => new Link(
            fromClass: GrandSon::class, 
            fromProperty: 'grandfather'
            )
    ],
    operations: [new Get()]
)]
class GrandFather extends Model
{
    protected $table = 'grand_fathers';
    protected $primaryKey = 'id_grand_father';
    protected $fillable = ['name','sons'];

    #[ApiProperty(genId: false, identifier: true)]
    private ?int $id_grand_father;

    private ?string $name = null;

    private ?Collection $sons = null;

    /**
     * @return HasMany
     */
    public function sons(): HasMany
    {
        return $this->hasMany(GrandSon::class,'grand_father_id','id_grand_father');
    }

}

GrandSon

<?php

namespace App\Models;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

#[ApiResource()]
#[ApiResource(
    uriTemplate: '/grand_fathers/{id_grand_father}/grand_sons',
    uriVariables: [
        'id_grand_father' => new Link(
            fromClass: GrandFather::class, 
            fromProperty: 'sons'
            )
    ],
    operations: [new GetCollection()]
)]
class GrandSon extends Model
{
    protected $table = 'grand_sons';
    protected $primaryKey = 'id_grand_son';
    protected $fillable = ['name','grand_father_id','grandfather'];

    #[ApiProperty(genId: false, identifier: true)]
    private ?int $id_grand_son;
    
    private ?string $name = null;

    private ?GrandFather $grandfather= null;

    /**
     * @return BelongsTo
     */
    public function grandfather(): BelongsTo
    {
        return $this->belongsTo(GrandFather::class,'grand_father_id','id_grand_father');
    }
}

Created Using Following Migrations:

GrandFather:

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('grand_fathers', function (Blueprint $table) {
            $table->increments('id_grand_father');
            $table->string('name');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('grand_fathers');
    }
};

GrandSon:

<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('grand_sons', function (Blueprint $table) {
            $table->increments('id_grand_son');
            $table->string('name');
            $table->unsignedInteger('grand_father_id')->nullable();
            $table->timestamps();
            $table->foreign('grand_father_id')->references('id_grand_father')->on('grand_fathers');

        });

    }

    public function down(): void
    {
        Schema::dropIfExists('grand_sons');
    }
};

Creates 2 Endpoints:

  1. /api/grand_fathers/{id_grand_father}/grand_sons

Calling:

curl -X 'GET' \
  'http://localhost:8008/api/grand_fathers/1/grand_sons?page=1' \
  -H 'accept: application/ld+json'

Works Properly and returns all GrandSons belonging to GrandFather with id_grand_father = {id_grand_father}

  1. /api/grand_sons/{id_grand_son}/grand_father

Carlling:

curl -X 'GET' \
  'http://localhost:8008/api/grand_sons/1/grand_father' \
  -H 'accept: application/ld+json'

Returns Error:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'grand_sons.grand_father_id' in 'where clause' (Connection: mysql, SQL: select * from `grand_fathers` where `grand_sons`.`grand_father_id` = 1 limit 1)"`

As you can see, the query is missformed.

Possible Solution

I think commit 5818e80 fixed BelongsToMany Relation but still is not manageing BelongsTo Relations.

My suggestion is adding the following code after managing BelonsToMany Relations here

EDIT

The correct code should be:

...
            // BelongsTo Relation
            if(method_exists($relation->{$from}(), 'dissociate')) 
            {    
                return $builder->getModel()->where($builder->getModel()->getQualifiedKeyName(), $identifier);
            }
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions