statamic-rad-pack / runway

Eloquently manage your database models in Statamic.
https://statamic.com/runway
MIT License
107 stars 42 forks source link

BelongsTo relation with differing foreignKey and primaryKey not resolving correctly #527

Open j6s opened 2 weeks ago

j6s commented 2 weeks ago

Description

When using a BelongsToFieldType on a column that points to a field different from the primary key of the related model, the field does not resolve the relationship correctly.

This might sound a bit esotheric, but might happen if an application is transitioning from numeric IDs to UUIDs and has to do so slowly due to external constraints.

Steps to reproduce

Example: A report always belongs to a location. Both, the report have a id (numeric) and uuid columns, of which the uuid is defined as primaryKey from eloquents point of view. The location_id on the Report still points to the id though.

// Location uses `uuid` as primary key
class Location extends Model {
    use HasUuids;
    protected $primaryKey = 'uuid';
}

// Report uses `uuid` as primary key
class Report extends Model {
    use HasUuids;
    protected $primaryKey = 'uuid';

    // The relationship still points to the `id` field of the location though
    public function location()
    {
        return $this->belongsTo(Location::class, 'location_id', 'id');
    }
}

Environment

Application Name: redacted Laravel Version: 11.10.0 PHP Version: 8.2.15 Composer Version: 2.7.2 Environment: local Debug Mode: ENABLED URL: redacted.ddev.site Maintenance Mode: OFF

Cache Config: NOT CACHED Events: NOT CACHED Routes: NOT CACHED Views: CACHED

Drivers Broadcasting: log Cache: statamic Database: mysql Logs: _console / stack, stderr Mail: smtp Queue: sync Session: file

Livewire Livewire: v3.5.0

Sentry Enabled: YES Environment: local Laravel SDK Version: 4.6.0 PHP SDK Version: 4.8.0 Release: f7aa4ce Sample Rate Errors: 100% Sample Rate Performance Monitoring: CUSTOM SAMPLER Sample Rate Profiling: 100% Send Default PII: DISABLED

Statamic Addons: 20 Sites: 2 (Deutsch, English) Stache Watcher: Disabled Static Caching: Disabled Version: 5.7.3 PRO

Statamic Addons appswithlove/statamic-one-click-content-translation: 5.2.3

jonassiewertsen/statamic-livewire: 3.5.0 mitydigital/sitemapamic: 3.0.2 mitydigital/statamic-scheduled-cache-invalidator: 2.0.5 reachweb/locale-lander: 3.0.0 rias/statamic-redirect: 3.7.1 ryanmitchell/statamic-translation-manager: 2.0.0 statamic-rad-pack/meilisearch: 3.3.0 statamic-rad-pack/runway: 7.4.0 statamic/eloquent-driver: 4.3.0 studio1902/statamic-peak-browser-appearance: 3.5.0 studio1902/statamic-peak-commands: 2.7.0 studio1902/statamic-peak-seo: 7.5.0 studio1902/statamic-peak-tools: 3.4.3

Statamic Eloquent Driver Asset Containers: file Assets: eloquent Blueprints: file Collection Trees: file Collections: file Entries: eloquent Forms: file Global Sets: file Global Variables: file Navigation Trees: file Navigations: file Revisions: file Taxonomies: file Terms: eloquent Tokens: file

j6s commented 2 weeks ago

After debugging this for a bit, I found 2 potential fixes for the issue, one in Runway, on in the application itself:

Runway

For runway to support this out of the box, PreparesModel would have to resolve the relationship itself similar to the additions in the following screenshot:

image

Application

I found adding attribute getter and setter for the 'true' primary key of the relation (in my example uuid) and using those in the belongsTo configuration also works.

    public function getLocationUuidAttribute(): string
    {
        return (string) $this->location()->pluck('uuid')->first();
    }

    public function setLocationUuidAttribute(string $uuid): void
    {
        $relation = $this->location();
        $location = $relation->getRelated()->where('uuid', $uuid)->first();
        $relation->dissociate();
        $relation->associate($location);
    }
-
  handle: location_uuid
  field:
    relationship_name: location
    resource: location
    type: belongs_to

If it is not in Runways interest to implement this feature (which is somewhat esotheric, I must admit), then feel free to close this Issue.

duncanmcclean commented 2 weeks ago

Are you able to provide an example repository that I can use to do some testing with? It might be relatively easy to fix but it might not, I need to dig in 😆