Support the ongoing development of Laravel.io →
Alpine.js Breeze Blade

I have three tables users, addresses and a morph pivot table addressables that looks like this:

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('addressables', function (Blueprint $table) {
            $table->foreignId('address_id')->constrained()->onDelete('cascade');
            $table->unsignedBigInteger('addressable_id');
            $table->string('addressable_type', 20); // user, club, company
            $table->string('type', 20)->default('home_address');

            $table->unique(['address_id', 'addressable_id', 'addressable_type', 'type'], 'addressables_index');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('addressables');
    }
};

I also have an AddressController with method store:

public function store(AddressRequest $request): RedirectResponse
    {
        if ($request->filled('id')) {
            // Use existing address
            $address = Address::findOrFail($request->input('id'));
        } else {
            // Create new address
            $address = Address::create($request->validated());
        }
        Log::info('Address: ' . $address);

        // Get the addressable type and log it
        $addressableType = $request->input('addressable_type');
        Log::info('Addressable Type: ' . $addressableType);

        // Assuming $addressableType is a fully qualified class name, e.g., App\Models\User
        $addressable = $addressableType::find($request->input('addressable_id'));

        // Use the relationship to attach the address
        $addressable->addresses()->attach($address, ['type' => $request->input('type')]);

        return redirect()->back()->with('success', 'Address added successfully.');
    }

and here is my blade component submitting a request to the store method:

{{-- This component is used to create new address or attach existing address to edited addressable --}}
<div x-data="{ showForm: false }">
    <div class="flex justify-start gap-2 pt-2">
        <h2 class="font-bold">{{__("Address")}}</h2>
        <button type="button" id="add-address-button" @click="showForm = !showForm">
            <i :class="showForm ? 'fa-regular fa-circle-xmark' : 'fa-regular fa-square-plus'"></i>
        </button>
    </div>
    <template x-if="showForm">
        <div x-data="addressFormComponent()" class="p-2 bg-amber-100 address">
            <form method="POST"
                  action="{{route('address.store')}}"
                  class="space-y-2"
                  @submit.prevent="handleSubmit">
                @csrf

                <!-- Hidden inputs for addressable -->
                <input type="hidden" name="addressable_id" value="{{ $addressable->id }}">
                <input type="hidden" name="addressable_type" value="{{ addslashes(get_class($addressable)) }}">

                <!-- Address Type Dropdown -->
                <div>
                    <x-input-label for="type" :value="__('Address Type')"/>
                    <select id="type"
                            name="type"
                            x-model="selectedType"  {{-- Bind the value of the select element --}}
                            class="block w-auto rounded-md border-0 py-2 font-bold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:max-w-xs sm:text-sm sm:leading-6">
                            required>
                        <option value="home_address">{{__("home_address")}}</option>
                        <option value="billing_address">{{__("billing_address")}}</option>
                    </select>
                    <x-input-error :messages="$errors->get('type')" />
                </div>

                <!-- id Field -->
                <input type="hidden" name="id" id="address_id" x-model="id">

                <!-- Care Of Field -->
                <div>
                    <x-input-label for="care_of" :value="__('Care of')" />
                    <x-text-input id="care_of" name="care_of" :value="old('care_of')" x-bind:disabled="addressSelected"/>
                    <x-input-error :messages="$errors->get('care_of')" />
                </div>

                <!-- Street Address Field -->
                <div>
                    <x-input-label for="street_address" :value='__("Street")' />
                    <x-text-input id="street_address" name="street_address" x-model="street" @input="searchAddresses" x-bind:disabled="addressSelected" required/>
                    <x-input-error :messages="$errors->get('street_address')" />
                </div>

                <!-- Postcode and City Fields -->
                <div class="flex gap-2">
                    <div>
                        <x-input-label for="postcode" :value='__("Postcode")' />
                        <x-text-input id="postcode" name="postcode" x-model="postcode" @input="searchAddresses" x-bind:disabled="addressSelected" required/>
                        <x-input-error :messages="$errors->get('postcode')" />
                    </div>
                    <div>
                        <x-input-label for="city" :value='__("City")' />
                        <x-text-input id="city" name="city" x-model="city" @input="searchAddresses" x-bind:disabled="addressSelected" required/>
                        <x-input-error :messages="$errors->get('city')" />
                    </div>
                </div>

                <!-- Address Search Results -->
                <div id="address-results" x-show="searchResults.length > 0" class="mt-2">
                    <!-- Display search results here -->
                    <ul>
                        <li>{{__("Click on address below if it exactly matches yours.")}}</li>
                        <template x-for="address in searchResults" :key="address.id">
                            <li>
                                <button type="button" @click="selectAddress(address)">
                                    <!-- Display address details -->
                                    <span x-text="address.street_address"></span>,
                                    <span x-text="address.postcode"></span>,
                                    <span x-text="address.city"></span>
                                </button>
                            </li>
                        </template>
                    </ul>
                </div>

                <!-- Submit Button -->
                <div>
                    <x-primary-button type="submit" x-bind:disabled="isDuplicate" @mouseover="enableFields">
                        {{ __("Save Address") }}
                    </x-primary-button>
                </div>
            </form>
        </div>
    </template>
</div>

<script>
    function addressFormComponent() {
        return {
            id: null,
            street: '',
            postcode: '',
            city: '',
            searchResults: [],
            addressSelected: false,
            addressablesAddresses:[],
            selectedType: '',
            isDuplicate: false,

            init() {
                // Watch for changes in selectedType
                this.$watch('selectedType', () => {
                    this.checkDuplicateAddress();
                });

                // Initialize selectedType with the default value of the select element
                this.selectedType = document.getElementById('type').value;
            },

            // Search database for addresses similar to what you type into the form fields
            async searchAddresses() {
                if (this.street.length < 3 && this.postcode.length < 3 && this.city.length < 3) {
                    this.searchResults = [];
                    return;
                }

                try {
                    const response = await fetch(
                        `{{ route('addresses.search') }}?street=${encodeURIComponent(this.street)}&postcode=${encodeURIComponent(this.postcode)}&city=${encodeURIComponent(this.city)}`
                    );
                    if (response.ok) {
                        this.searchResults = await response.json();
                    } else {
                        console.error('Error fetching address search results:', response.statusText);
                    }
                } catch (error) {
                    console.error('Error fetching address search results:', error);
                }
            },

            // Select an existing address from database
            async selectAddress(address) {
                // Implement the functionality to select an address from the search results
                console.log('Selected address:', address);

                // Set form fields with the selected address details if needed
                this.id = address.id;
                this.street = address.street_address;
                this.postcode = address.postcode;
                this.city = address.city;
                this.searchResults = [];
                this.addressSelected = true; // Disable fields

                // Fetch attached addresses id and type
                try {
                    const response = await fetch(
                        `{{ route('addressables.addresses', ['addressable_id' => $addressable->id, 'addressable_type' => 'ADDRESSABLE_TYPE_PLACEHOLDER']) }}`
                        .replace('ADDRESSABLE_TYPE_PLACEHOLDER', encodeURIComponent('{{ addslashes(get_class($addressable)) }}'))
                    );

                    if (response.ok) {
                        this.addressablesAddresses = await response.json();
                        console.log(this.addressablesAddresses);
                        this.checkDuplicateAddress();
                    }
                } catch (error) {
                    console.error('Error fetching addresses:', error);
                }
            },

            // Used to disable submit button since storing duplicates would cause unique index violation
            checkDuplicateAddress() {
                this.isDuplicate = this.addressablesAddresses
                    .some(addressable => addressable.address_id === this.id && addressable.type === this.selectedType);
                console.log('Check, duplicateAddress is: ' + this.isDuplicate);
            },

            // Enable fields before form submission
            enableFields() {
                this.addressSelected = false;
            },

            // Handle form submission
            handleSubmit(event) {
                // Enable fields before submitting the form
                this.enableFields();

                // Submit the form programmatically
                event.target.submit();
            }
        };
    }

    document.addEventListener('alpine:init', () => {
        Alpine.data('addressFormComponent', addressFormComponent);
    });
</script>

The component is icluded in a user\edit.blade.php like this:

                    <!-- Add Address Component -->
                    <x-add-address-form :addressable="$user" />

My problem is that when I submit the form I am getting this output to the log:

[2024-06-07 13:20:07] local.INFO: Address: {"id":1,"care_of":null,"street_address":"Solberga Nordg\u00e5rden 1","city":"Sjuntorp","postcode":"461 97","region":null,"created_at":"2024-06-02T20:07:07.000000Z","updated_at":"2024-06-02T20:07:07.000000Z"}  
[2024-06-07 13:20:07] local.INFO: Addressable Type: App\\Models\\User  
[2024-06-07 13:20:07] local.ERROR: Cannot declare class App\Models\User, because the name is already in use {"userId":1,"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\FatalError(code: 0): Cannot declare class App\\Models\\User, because the name is already in use at C:\\Users\\larsf\\PhpStormProjects\\Pegasos\\app\\Models\\User.php:11)
[stacktrace]
#0 {main}
"} 

I of course have a Models\User class for the user and it looks like Laravel is trying to create a new Models/User class when this line of code is executed:

        // Assuming $addressableType is a fully qualified class name, e.g., App\Models\User
        $addressable = $addressableType::find($request->input('addressable_id'));

Why is this happening, and how can I modify my code to prevent this?

0

Can you publish the User and Address Model?

0

The times I encounter this error is when I defined the same model name (User in your case) in another Model. So, instead of the model name matching the filename, I inadvertently used a model name already defined elsewhere. The other way I encountered this error was when I defined the model more than once in the Controller. Both are "duhhhhh" moments, for me that is.

I was able to usually find this error, including the offending file(s) while doing a "composer update".

0

Sign in to participate in this thread!

PHPverse

Your banner here too?

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2025 Laravel.io - All rights reserved.