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

ChristopherSFSD's avatar

Eloquent Model set properties during or right after __construction

So I have this complex model that represents a part -- we'll say a computer part. The vendor supplies a limited amount of data that I pull into the database. From there I have written many functions (inside the part model class) that are used to interpret that data. As it stands, the model currently calls the same functions many times as it parses through the data which is causing it to perform more slowly than I would like.

I tried creating new properties on the class and populate them using the __construct method (yes calling the parent first) but the properties refuse to be set. They end up as null. What I'd like to do is accomplish what, in theory, the following should do but doesn't ...

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

use Exception, Session;
use Illuminate\Http\Request;

class Part extends Model
{
	public foo_property; // Getting this property after the model is instantiated results in 'null'

	public function __construct()
	{
		parent::__construct();
		$this->foo_property = $this->get_foo_property();
	}

	public function get_foo_property()
	{
		return 'Foo';
	}
}

This way I can call all of my various methods just once and rely on the properties to perform the rest of my calculations.

What am I missing?

Thanks in advance for any help?

0 likes
10 replies
tykus's avatar

Overriding the Model constructor is fraught. The correct signature is public function __construct(array $attributes = []); but you are not accepting the array of attributes (or passing them to the parent). Is there a reason for the getter; can't you simply set the default attributes on the Model instead???

ChristopherSFSD's avatar

Admittedly I simplified the code sample. In my testing I was passing the attributes but getting the same result. I'm okay with not using the constructor at all as long as something else fires automatically after the constructor that can then set properties on the model.

Regarding "default attributes" I'm not entirely sure what you mean. Being an eloquent model it has properties that match the fields in the database. I want to set a whole bunch of additional properties that are not fields in the database and I need to do it right after the model has been instantiated.

Hopefully I'm making sense.

tykus's avatar

@[email protected]

Being an eloquent model it has properties that match the fields in the database

Actually, being an Eloquent it has an array of attributes which are magically (using the __get method) available as properties.

Having properties on a Model that are not represented in the database table will cause you headaches if you don't explicitly defined the $fillable columns

ChristopherSFSD's avatar

Understood. I guess I still don’t know how that solves my problem. For example I’m currently calling $this->vendor_cost() many times on the model. Vendor cost is not a field in the table. I’d rather set a properly or whatever on the model by calling the vendor_cost method once so the rest of the code can just use the property.

tykus's avatar

@[email protected] what is vendor_cost method doing exactly?

Did you consider making an Accessor; it will be evaluated only once (per Part instance) and thereafter you get the result from the previous time the property was accessed.

Snapey's avatar

I would consider creating a DTO or value object, which ultimately you could pass straight into the create function of the model.

Your DTO can include a fromAPI method or similar, which accepts the data from the vendor in whatever format they provide it, and then update all the interior properties of the DTO based on the passed in data. Attributes could have default values for anything that might not be passed.

Then when it is prepared, you can pass this object to the model ?

ChristopherSFSD's avatar

As it turns out, using the model's retrieved event isn't quite working because retrieved happens before relationships are loaded.

I looked at creating accessors but as best I can tell accessors are for properties on the model -- aka, fields that exist in the model's table. Perhaps I'm not understanding this correctly.

For example I have a method on the model called line() -- which is for the product line. That method only needs to be called once but accessed dozens of times throughout the lifecycle and it needs to be able to access the related models that are eager loaded. Therefore it's logical to me that after the model is constructed, I would just set a property on the model that holds the result of the line method and then access that property instead of re-executing that method over and over and over again.

I need to be able to run model methods to set other properties after the model is fully instantiated, relationships loaded, etc.

ChristopherSFSD's avatar

I guess in my line() method I could:

if (isset($this->line)) return $this->line;

I'd have to do this for dozens of methods, and it feels messy and unnecessary. It seems like there should be a better way to set arbitrary properties on a model by calling methods on the model immediately after construction is complete and after relationships are retrieved.

Please or to participate in this conversation.