Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

oronatur's avatar

What does it mean when there's a => #number in the dd of an array?

I'm getting some data from the database and trying to do a foreach on it, though nothing prints. When I do a dd() on the array, I get this:

array:1 [▼ // path/to/file 0 => {#1594 ▶} ]

What does the #1594 mean? I wasn't able to formulate this well enough to do a google search on it, so I hope someone here has encountered this before.

0 likes
36 replies
oronatur's avatar
array:1 [▼ // path/to/file
  0 => {#1594 ▼
    +"player_id": 8
    +"palace_id": 1
    +"palace": 1
    +"barracks_id": 2
    +"barracks": 0
    +"library_id": 3
    +"library": 0
    +"granary_id": 4
    +"granary": 0
    +"id": 4
    +"building_name": "Granary"
    +"building_max_level": 20
    +"building_description": "Granary description"
    +"building_cost_gold": 5
    +"building_cost_wood": 100
    +"building_cost_stone": 100
    +"building_cost_sand": 0
    +"building_cost_copper": 0
    +"building_cost_tin": 0
    +"building_cost_iron": 0
    +"building_cost_silver": 0
    +"building_cost_bronze": 0
    +"building_cost_steel": 0
    +"building_cost_glass": 0
    +"building_cost_mithril": 0
  }
]

I don't think it's the elements, this is what's in it. Edit: forgot formatting

tykus's avatar

Internal PHP reference for an object.

oronatur's avatar

@tykus So the array contains an object instead of another array? Maybe that's why I can't get the foreach to print anything..

tykus's avatar

@oronatur yes; and the + means the property is public.

array:1 [▼
  0 => {#1594 ▼
    +"player_id": 8

Is this the result of json_decode; did you forget to set the second argument to true?

oronatur's avatar

@tykus No, it's what I get from this:


$sql = DB::select(DB::raw("SELECT building_levels.$name, buildings.*  FROM building_levels INNER JOIN buildings ON building_levels.$var_id = buildings.id WHERE player_id = $userID"));
$buildingInfo[] = $sql;

This is in a foreach (well, the array is defined outside it). I couldn't quite get it to work with eloquent so I just did it this way. Do you by any chance know how I can change it so that it returns as an array? I tried toArray, but I get "expected type object, found array)"

Edit: Oh, and, for testing purposes, I am currently returning $sql, not $buildingInfo. compact('sql')

tykus's avatar

@oronatur no concerns about SQL injection at all?

Otherwise, a Collection of stdClass objects is the expected result of a Query Builder query.

oronatur's avatar

@tykus No, this is only something I'm doing for fun. It's only local and will never go live, so I figured I'd get back to it when I was looking at the security aspect of it.

Yeah, I thought so, but then why do I get "expected type object, found array" when I try to use toArray()?

oronatur's avatar

@tykus I was able to make it work with this now:

$sql = DB::table("building_levels")
                ->Join("buildings", function($join) use ($var_id, $userID) {
                    $join->on("building_levels.$var_id", "=", "buildings.id");
                })
            ->select("building_levels.$name", "buildings.*")
            ->where("player_id", "=", $userID)
            ->get();
            $sql = $sql->toArray();

which, in dd, return

Illuminate\View\View {#1604 ▼ // path/
  #factory: Illuminate\View\Factory {#207 …23}
  #engine: Illuminate\View\Engines\CompilerEngine {#320 ▶}
  #view: "palace.palace"
  #data: array:1 [▼
    "sql" => array:1 [▼
      0 => {#1596 ▼
        +"granary": 0
        +"id": 4
        +"building_name": "Granary"
        +"building_max_level": 20
        +"building_description": "Granary description"
        +"building_cost_gold": 5
        +"building_cost_wood": 100
        +"building_cost_stone": 100
        +"building_cost_sand": 0
        +"building_cost_copper": 0
        +"building_cost_tin": 0
        +"building_cost_iron": 0
        +"building_cost_silver": 0
        +"building_cost_bronze": 0
        +"building_cost_steel": 0
        +"building_cost_glass": 0
        +"building_cost_mithril": 0
      }
    ]
  ]
  #path: "/path"
}

However, I am still unable to make a foreach of it print anything, not even a echo "hello"; I was able to use toArray now, but it still doesn't seem to be one..

kokoshneta's avatar

@oronatur You’re dd()’ing a view object there, not an array. Your SQL still appears to have the same structure.

The expected result is still a collection, though, not a generic object. What is the output if you paste this precise code into your controller (or wherever your code is being executed)?

$building_levels = DB::table("building_levels")
	->join("buildings", function($join) use ($var_id) {
		$join->on("building_levels.$var_id", "=", "buildings.id");
	})
	->select("building_levels.$name", "buildings.*")
	->where("player_id", "=", $userID)
	->get()
;

dd($building_levels);
oronatur's avatar

@kokoshneta

Then I get:

Illuminate\View\View {#1604 ▼ // path
  #factory: Illuminate\View\Factory {#207 …23}
  #engine: Illuminate\View\Engines\CompilerEngine {#320 ▶}
  #view: "palace.palace"
  #data: array:1 [▼
    "building_levels" => Illuminate\Support\Collection {#1605 ▼
      #items: array:1 [▼
        0 => {#1602 ▼
          +"granary": 0
          +"id": 4
          +"building_name": "Granary"
          +"building_max_level": 20
          +"building_description": "Granary description"
          +"building_cost_gold": 5
          +"building_cost_wood": 100
          +"building_cost_stone": 100
          +"building_cost_sand": 0
          +"building_cost_copper": 0
          +"building_cost_tin": 0
          +"building_cost_iron": 0
          +"building_cost_silver": 0
          +"building_cost_bronze": 0
          +"building_cost_steel": 0
          +"building_cost_glass": 0
          +"building_cost_mithril": 0
        }
      ]
      #escapeWhenCastingToString: false
    }
  ]
  #path: "/path"
}

I got it to work in a way though. It isn't pretty, but it works.

$sql = DB::table("building_levels")
                ->join("buildings", "building_levels.$var_id", "=", "buildings.id")
                ->select("building_levels.$name", "buildings.*")
                ->get();

            $sql = object_to_array($sql);
            $buildingInfo[] = $sql;
public static function object_to_array($data) {
        if (is_array($data) || is_object($data)){
            $result = [];
            
            foreach ($data as $key => $value) {
                $result[$key] = (is_array($value) || is_object($value))
				 ? object_to_array($value) : $value;
            }

            return $result;
        }

        return $data;
    }

I still can't get anything out of the foreach though.. This is the array, dd of $unbuiltBuildings:

Illuminate\View\View {#1604 ▼ // resources/views/palace/partials/buildings.blade.php
  #factory: Illuminate\View\Factory {#207 …23}
  #engine: Illuminate\View\Engines\CompilerEngine {#320 ▶}
  #view: "palace.palace"
  #data: array:1 [▼
    "buildingInfo" => array:4 [▼
      0 => array:17 [▼
        "palace" => 1
        "id" => 1
        "building_name" => "Palace"
        "building_max_level" => 10
        "building_description" => "Palace description"
        "building_cost_gold" => 0
        "building_cost_wood" => 0
        "building_cost_stone" => 0
        "building_cost_sand" => 0
        "building_cost_copper" => 0
        "building_cost_tin" => 0
        "building_cost_iron" => 0
        "building_cost_silver" => 0
        "building_cost_bronze" => 0
        "building_cost_steel" => 0
        "building_cost_glass" => 0
        "building_cost_mithril" => 0
      ]
      1 => array:17 [▶]
      2 => array:17 [▶]
      3 => array:17 [▶]
    ]
  ]
  #path: "/home/tommy/ages/resources/views/palace/palace.blade.php"
}

How would I write the foreach to make it list this out? I'm doing:


foreach($unbuiltBuildings as $unbuiltBuilding) {
								echo "test";
}

And it prints absolutely nothing. No errors either.

Edit: I just needed to use foreach($unbuiltBuildings['buildingInfo'] as $unbuiltBuilding)

kokoshneta's avatar

@oronatur That’s still very, very, very strange. That shows a dump of a view, which has nothing at all to do with database queries.

Are you sure you aren’t dd()’ing something else at an earlier stage in your code? There is absolutely no way that the code I wrote in my previous comment can give the output you show here.

Where is your code located? Is it in a controller? A model method? Somewhere else? Can you show it in context?

And also, why do you want to convert the collection to an array?

oronatur's avatar

@kokoshneta I might very well be going around this the wrong way. I am nothing but a codemonkey with questionable googling skills. I realize now that I might have misunderstood your earlier post. I am dd'ing in my view, as I didn't know there was a way to use that directly in the controller. I'm doing the logic in a controller, and then passing it to my view using return view('palace.palace', compact('buildingInfo'));

The code is located in a controller. I'll show you the entire thing:

    public static function buildingInfo () {
        $buildingNames = Buildings::pluck('building_name');        
        $userID = Auth::user()->id;
        $buildingInfo = [];

        foreach($buildingNames as $buildingName){
            $name = strtolower($buildingName);
            $var_id = $name . "_id";
            $sql = DB::table("building_levels")
                ->join("buildings", "building_levels.$var_id", "=", "buildings.id")
                ->select("building_levels.$name", "buildings.*")
                ->get();

            $sql = PalaceController::object_to_array($sql);
            $buildingInfo[] = $sql;
        }

        $buildingInfo = array_reduce($buildingInfo, 'array_merge', array());
        array_reduce($buildingInfo, 'array_merge', array());

        return view('palace.palace', compact('buildingInfo'));
    }

    public static function object_to_array($data) {
        if (is_array($data) || is_object($data)){
            $result = [];
            
            foreach ($data as $key => $value) {
                $result[$key] = (is_array($value) || is_object($value)) ? PalaceController::object_to_array($value) : $value;
            }

            return $result;
        }

        return $data;
    }

Like I wrote above, I've got it to work now, but it feels a bit hacky.. I'm converting it to an array so that I can use a foreach to show all the available info in rows in my view. Is there another way that is supposed to be done? I'm calling the controller from the view, it passes back an array with the info I need, which I then list out with a foreach.

kokoshneta's avatar

@oronatur All right, several things here. Please read this through carefully, because there are a lot of questions, and it’s not really possible to help you properly without knowing the answer to all of them.

First off, why is the function static? There’s very rarely a need for static functions in controllers. Normally, your controller would be instantiated.

Secondly, I don’t understand your column names. You have a building_name column in your buildings table whose value corresponds to the name of a column in the building_levels table? And then there’s a (foreign ID?) column in building_levels whose name is made up of that same value + _id? So for every possible value of buildings.building_name, there are two corresponding rows in building_levels? For example, if buildings.building_name = library, you would have building_levels.library and building_levels.library_id as well?

If this is correct, it sounds to me like you need a pivot table, because that’s way too complex and fragile for one table. (Also, column names are not case sensitive in SQL, so you don’t need to call PHP functions to lowercase them.)

Thirdly, there’s no need to jump through all those hoops to convert the collection into an array. Collections are traversable, so foreach works just fine on them. And all that array-reducing… what is that even supposed to do?

Fourthly – and perhaps most importantly – what exactly are you trying to select? What kind of structure are you hoping to get back? As far as I can guess, it would be a collection or an array of building info (joined row containing buildings.* plus building_levels.[building_name]_id), but grouped by building_name (so all the buildings where building_name = hotel would be grouped into one, etc.). Is that right?

There’s no real way to properly solve this without understanding the relationships between the tables, but (if my assumptions above are correct) the following should at least work, even if it’s not exactly elegant or efficient:

// Controller

namespace App\Http\Controllers;

use Illuminate\Database\Eloquent\Collection;

class PalaceController extends Controller {
	public function buildingInfo () {
		$buildingNames = Building::pluck('building_name');
		$buildingInfo = new Collection;

		foreach ($buildingNames as $name) {
			$column = "{$name}_id";

			$buildingInfo = $buildingInfo->merge(DB::table("building_levels")
				->join("buildings", "building_levels.$var_id", "=", "buildings.id")
				->select("building_levels.$name", "buildings.*")
				->get()
			);
		}

		$buildingInfo = $buildingInfo->groupBy('building_name');

		// Show all the fetched data, and just that
		dd($buildingInfo);

		return view('palace.palace', compact('buildingInfo'));
	}
}

// View

<div>
	<h1>Heading</h1>

	@foreach ($buildingInfo as $type => $buildings)
		<h2>Buildings of type {{ $type }}</h2>

		@foreach ($buildings as $building)
			{{ $building->someProperty }}
		@endforeach
	@endforeach
</div>
kokoshneta's avatar

@oronatur I just noticed this at the end of your previous comment:

I'm calling the controller from the view, it passes back an array with the info I need, which I then list out with a foreach.

What?! You’re calling the controller from the view? Why? You call the view from the controller, not the other way around.

The life cycle goes like this:

  • Route definition matches the URL to a controller method; e.g., the URL /palaces/details leads to the buildingInfo() method in the PalaceController
  • The controller method fetches and prepares the data to display in the view
  • The controller method creates and returns the view (using view()) and passes the data along
  • The view uses the data to display in an HTML structure
oronatur's avatar

@kokoshneta Hi! Thanks for typing all that out, I really appreciate it.

So, first off, it's probably related to why I'm calling the controller from the view as you added below. I made the functions static because they wouldn't run otherwise - I got an error saying you couldn't call a non static function. The reason why I'm calling it from the view is because I couldn't figure out how to add a route to more than one method in the same view. The index method returns the view in the proper way, but when I then needed to call some more methods from that class for different parts of that view, I could not get it to work at all. I figured bad code was worse than no code, and just called the method from the view.

Secondly: I am making a text based game. In this game you can build different buildings, and they have different effects depending on what level they are. The building_levels table have a player_id column, a column for building id, and one for the level - this column is just called the name of the building. In the buildings table I have the complete list of all the buildings, with its id, name, effect, cost, upgrade cost, +++. building_levels.palace_id, for example, corresponds to the id of the row that has all the info on the palace in it. I was not aware that they were not case sensitive, so thanks for that.

Thirdly: Is there a special way you have to foreach the collection? I tried different things for close to an hour but was unable to get the info out. I reduced the array because the end result of all this tinkering with the query gave me an array that contained array for all the buildings (which I wanted) but the info I wanted in these for arrays down two levels of arrays that didn't have any purpose. Ther reducing gave me array->array with info, instead of array->array->array->info. It's really just a fix for the monkeycode not giving me the formatting I wanted on the arrays it produced.

Fourth: what I'm trying to get is all the info from the building table, as well as the building level from the building_level table. I'm then using it to list out which buildings the player has built, what levels they have their buildings in, which they can still build, what it will cost to upgrade them, etc.

I made a game somewhat like this (but a lot simpler) in phpin the late 90s, but since I haven't touched php since, I'm trying to get into all the new things that have come out since then. OOP, MVC, all of this didn't even exist last time I was playing with this, so I appreciate you taking the time to walk me through my mistakes. Please let me know if there's something I didn't answer/explain properly.

kokoshneta's avatar

@oronatur Okay, so I think I mostly understand what you’re trying to do now, except I still don’t really see what you mean by ‘levels’ and what they actually consist of/contain. I can’t figure out if these are instantiated buildings (i.e., actual buildings that the player has built in the game) or the building types that are available for players to turn into actual instances of buildings.

Can you show some example rows from the buildings table, and some corresponding rows from the building_levels table? Do you have a BuildingLevel model corresponding to the building_levels table?

oronatur's avatar

@kokoshneta sure, these are some examples of the seeder that seeds the buildings. They are building types as you say, then have the info on the buildings as templates, you could say. I haven't implemented their effects yet, but I will add that to this table as well, i.e. building_1_effect, building_2_effect, etc, and which of the effects are active depends on the level of the players instance of this building and what level that is.

Buildings::create([
            'building_name' => 'Palace',
            'building_max_level' => '10',
            'building_description' => 'Palace description',
            'building_cost_gold' => '0',
            'building_cost_wood' => '0',
            'building_cost_stone' => '0',
            'building_cost_sand' => '0',
            'building_cost_copper' => '0',
            'building_cost_tin' => '0',
            'building_cost_iron' => '0',
            'building_cost_silver' => '0',
            'building_cost_bronze' => '0',
            'building_cost_steel' => '0',
            'building_cost_glass' => '0',
            'building_cost_mithril' => '0',
        ]);

        Buildings::create([
            'building_name' => 'Barracks',
            'building_max_level' => '20',
            'building_description' => 'Barracks description',
            'building_cost_gold' => '0',
            'building_cost_wood' => '50',
            'building_cost_stone' => '50',
            'building_cost_sand' => '0',
            'building_cost_copper' => '0',
            'building_cost_tin' => '0',
            'building_cost_iron' => '0',
            'building_cost_silver' => '0',
            'building_cost_bronze' => '0',
            'building_cost_steel' => '0',
            'building_cost_glass' => '0',
            'building_cost_mithril' => '0',
        ]);

building levels:

player_id: 8
palace_id: 1
palace: 1
barracks_id: 2
barracks: 0
library_id: 3
library: 0
granary_id: 4
granary: 0

Here you have one row per player, with the levels of their buildings, and that building types id, which is in the building table. In this case, palace id 1 = look for id 1 in the building table for the info. This player has palace = 1, that players instantiated (am I using this word right?) building is level 1, while the barracks, library and granary are level 0, i.e. not built yet. Yes, I have a BuildingLevels model, but it contains no functions or anything, I wasn't really sure if that was supposed to go in the model or controller so I put it all in the controller.

kokoshneta's avatar
Level 27

@oronatur Aha! Now we’re getting somewhere! Part of the confusion stems from your use of the word level, which doesn’t mean what I think you’re using it to mean (number, amount, sum total). Another part is that your database structure is very inefficient and hard to understand without seeing the actual data.

So, here’s what I understand now:

  • buildings holds the general information about building types, how much they cost to build, etc.
  • building_levels holds a list of how many of each type of building a player has actually built

So the only thing building_levels really does is connect players to buildings, with an additional counter. Each player can build multiple types of buildings (if they have the money/rights to, of course), and each type of building can be built by multiple players. That is a many-to-many relationship, and building_levels is a pivot table!

Pivot tables are essential in databases, and they are fundamental to many-to-many relationships in Laravel, which represents them as relationships between models. But the way you’ve set it up breaks how pivot tables work.

Below is how you would do it the Laravel way. Most of the work is restructuring your tables to make more sense, because your current structure is not very efficient and certainly not easy to select from using Eloquent.

Make a player model + table

Your model should be called Player and your table should be players. This will contain all the details about the user – name, nickname, avatar, e-mail/username, player level, etc. It should have an ID column called just id.

Make a building model + table

This is the Building model and buildings table that you already have. If I understand you correctly, you currently only have four types of buildings available (palaces, barracks, libraries and granaries – making for a very odd town!), but I assume more could be added later on.

I don’t think you need to change anything in your buildings table, except I would change all the column names by removing the building_ part at the beginning – it’s obvious that things in the buildings table relate to buildings – and rename max_level to something like max_count or max_per_user, since I’m guessing that refers to how many of this type of building a user can build.

This table also needs an ID column just called id.

Make a pivot table

Your pivot table should be named building_player (not building_level!) for Laravel’s auto-features to work. It should have the following columns:

  • player_id
  • building_id
  • count

In this table, you can have multiple rows per player – one row for each building type. This is the main difference from your current table structure: instead of a single row per user containing the count of all the different building types, here we have one row per building type per user, containing only the building type’s ID (not name) and how many of that building type this user has made.

Your migration to create the table would look like this:

public function up() {
	Schema::create('building_player', function (Blueprint $table) {
		$table->foreignId('player_id')->constrained();
		$table->foreignId('building_id')->constrained();
		$table->integer('count');

		$table->unique(['player_id', 'building_id']);
	});
}

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

(The ID columns in your player and building tables should also be created using $table->id() for the foreign keys to work.)

Load your players’ relationships

What you’re after is an overview of the buildings made by a player – that is essentially what model relationships do. A player can have a number of building types associated with them, which are loaded as properties on the player model.

As mentioned above, your relationship here is a many-to-many relation (each player can related to many types of building, each building type can relate to many users). The way the tables have been set up above is intended to make Laravel’s many-to-many relationship functions work as easily as possible.

When you make a many-to-many relationship on your model, the model keys in the pivot table (player_id and building_id) are automatically brought in, but you have to specify if there are any additional columns you want to include as well (in this case, count).

In your player model, add a relationship for buildings:

// Player.php

public function buildings() {
	return $this->belongsToMany(Building::class)->withPivot('count');
}

And that’s pretty much it! You can now load any player’s buildings from anywhere. For example, let’s say you want an overview of player 123’s buildings. You have a PlayerController used to control data about players and pass it on to views that define how to output that data, and in that controller, you’d have a function that specifically fetches building info. You would make a route along these lines:

// web.php

Route::get('players/{player}/buildings', [PlayerController::class, 'buildings'])->name('player.buildings');

In your controller, this would be the relevant function – super simple:

// PlayerController.php

public function buildings(Player $player) {
	$player->load('buildings');

	return view('players.buildings', compact('player'));
}

The player model is automatically resolved by the service provider based on the {player} placeholder in the route representing the ID (here 123). Then we load the buildings() relationship by doing ->load('buildings').

The result is a model where $player->buildings is a collection of Building objects, each with a pivot property that contains a count property. So in your view, you can simply do this:

// players/buildings.blade.php

<section class="player-listing">
	<h1>All {{ $player->name }}’s buildings</h1>

	@foreach ($player->buildings as $building)
		<div class="building">
			<h2>{{ $building->name }}</h2>

			<p>Number of buildings: {{ $building->pivot->count }}</p>
		</div>
	@endforeach
</section>
1 like
oronatur's avatar

@kokoshneta Thank you for this, this is truly wonderful! I'll read it properly tomorrow when I have access to my computer again, but I wanted to clarify that the players will only be able to build one of each kind of building, (maybe with some later buildings they will be able to build two or three) but they will be able to upgrade them. Level 1 -> does a little bit, level 2 -> does a bit more, and so forth, up to max_level. Does that change anything in the setup you've described above? Which, again, is amazing, I've been googling this stuff for a week, and even made multiple posts on stackoverflow and reddit to ask for database design resources, but the way I've done it so far is the best I've been able to come up with. I'll definitly redo it like this tomorrow!

kokoshneta's avatar

@oronatur Oh, that’s what ‘level’ means!

No, that doesn’t change anything, except the name of the columns in the buildings and pivot table, which should then remain (max_)level instead of (max_)count.

The fact that the combination of player ID + building type ID is unique still means that there can only be one of each type. If the building should ‘level up’, you just increase the value of the level column. The rest works the same.

oronatur's avatar

@kokoshneta I've implemented the changes now, and I should be able to see the view at 127.0.0.1:8000/ players/buildings.blade.php, is that correct? I'm still not 100% sure how the pathing/routing works, but all I get at that adress is 404 so far. I might very well have done somethibg wrong while implementing it, I just thought I'd eliminate the path as the easiest solution first, haha

kokoshneta's avatar

@oronatur No, the part that you write as the first first argument to Route::get() is the full URL – you don’t add extensions. The part in {brackets} is a placeholder, so that needs something to be replaced by, an actual player’s ID from your database in this case. Let’s say you use player 1, the URL would then be 127.0.0.1:8000/players/1/buildings.

oronatur's avatar

@kokoshneta Ah, I see. Still 404 though, so I probably made a mistake somewhere. I've stored players as users, so I renamed the parts of your code that said player and players to user and users respectively, so I probably made a mistake there somewhere.

kokoshneta's avatar

@oronatur Try showing what your web.php routes file and your UserController look like, then we’ll see if something looks wrong there.

oronatur's avatar

@kokoshneta I managed to get it to work (I can't spell apparently), but I'm struggeling with Undefined variable $user

<section class="user-listing">

	<h1>All {{ $user->name }}’s buildings</h1>



	@foreach ($user->buildings as $building)

		<div class="building">

			<h2>{{ $building->name }}</h2>



			<p>Building level: {{ $building->pivot->level }}</p>

		</div>

	@endforeach

</section> 

web.php

Route::get('users/{user}/buildings', [UserController::class, 'buildings'])->name('user.buildings');

UserController

<?php

namespace App\Http\Controllers;
use App\Models\User;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function buildings(User $user) {
        $buildings = $user->load('buildings');
    
        return view('users.buildings', compact('buildings'));
    }
}

and Model, User.php

 public function buildings() {
        return $this->belongsToMany(Building::class)->withPivot('level');
    }
kokoshneta's avatar

@oronatur Hmm… everything looks correct. Have you made sure that you actually have a user with the ID that you’re providing in the URL? What URL exactly are you entering into your address bar?

(Of course, if the plan is to give each player an overview of their own buildings, at some point you’ll want to change it up so that the URL is something like /profile/buildings, and then you’ll fetch the authenticated user inside the buildings() function, rather than injecting it based on an ID provided in the URL – but since I’m guessing you don’t have authentication done yet, I figured it would be best to leave that for now.)

oronatur's avatar

@kokoshneta Yep, I double checked - the URL is "http://127.0.0.1:8000/users/8/buildings"

I've got that set up already - or rather, I installed Laravel Breeze and just highjacked that for my own purposes, and it came with user authentication premade. I just made a migration to add some columns to the user table. Could that be what is causing the error? Would it help if I gave you access to the github repository so you could look at everything there?

oronatur's avatar

@kokoshneta I got it to work. I had to use the Auth::user() thing, instead of $user.

Anyway, I'll take some time to process all of this and learn what is actually going on with the code you've given me. Thank you for all your help!

Edit: Uh, I, spoke to soon. I can't more entries to the building_user table, due to

ERROR 1062 (23000): Duplicate entry '1' for key 'building_user.PRIMARY'

I'm assuming it's due to this?

$table->unique(['user_id', 'building_id']);

Question is, do I just remove it, or is it responsible for something important I might be unaware of?

kokoshneta's avatar

@oronatur I would also recommend reading through the Laravel docs, pretty much from one end to the other. At least, read through all the parts in Getting Started, Architecture Concepts, The Basics, Digging Deeper, Database and Eloquent ORM.

It’s a lot to read, but it really does explain quite well how everything works and fits together, how things like routing, controllers, fluid database queries and all those things work together.

There’s also the Laracast series Laravel 8 from scratch, which illustrates it all very well as well (it’s Laravel 8 instead of 9, but most things are still the same). It’s long, but worth it.

kokoshneta's avatar

@oronatur Oops, sorry – that’s a mistake in the migration I made above. There shouldn’t be an ID column in the building_player pivot table. Just remove the ID column (or if you redo the migration, remove the $table->id() line).

The ->unique() call is responsible for making sure that each player can only build one instance of a particular building type (the combination of player ID + building type ID must be unique). Only remove that if you want players to be able to create multiple instances of the same building type.

oronatur's avatar

@kokoshneta I read the docs, but was left more than a bit confused at some areas. I will definitly give that series a look. Thanks for the tip! Perfect, works great now when I dropped the id column. Thanks again - your patience and help on all of this has been greatly appreciated!

kokoshneta's avatar

All entities available in the current scope (including all variables, arrays, models, collections, etc.) have a unique identifier that PHP uses to access them. Essentially pointers to a particular location in memory.

The number written as #12345 in grey in the dumps in Laravel are just those internal references written out as decimal numbers (though the Symfony dumper only seems to use them with objects). They don't serve much purpose to you, except if you ever need to verify whether two variables point to the same object or two different objects. Then they're extremely useful.

1 like
Dave Wize's avatar

@kokoshneta I must say that I'm astounded by your patience and kindness. @oronatur Laravel is easy to learn and master. I'm a beginner myself I understand your confusion it will soon click in :)

oronatur's avatar

@Dave Wize After all the help I've gotten in this thread I'm starting to grasp it, I think. The amounts of help and guidance I've gotten here is nothing less than amazing!

Please or to participate in this conversation.