artkonekt/concord

Use Laravel IOC

Closed this issue · 8 comments

Love this concept of packages/modules/boxes. Something that use to be in Laravel but was taken out post 4.2.

Perhaps using standard Laravel IOC would be better long run?

$this->app->bind('Custom/Module/Model', Model::class);

Using it via the Laravel IOC

$model = app()->make('Custom/Module/Model');

This also then works for model binding without having to implement manual binding

Route::get('/{product}', function(Custom/Module/Model $product) {
  return $product;
});

Hello Milos,

thanks for the feedback!
You're right about that, and it was designed to work with standard Laravel IOC.

The registerModel() method also silently binds the interface to the implementation with Laravel's service container so you can simply type hint the interface at any point where automatic injection happens.

This is described in depth in the Models Documentation.

This is the longest doc page, but actually contains all the whys and hows on this topic.

Actually the root of the problem is the model relationships.

  • If you 'hardcode' the hasMany/hasOne/... class in a module, it is difficult to change it in an app if the app wants to extend the Model.
  • You can't return the bound classname from the IOC for an Interface, (you can return an instance and use get_class on it, but I did not want that :) )

The code is actually shorter: https://github.com/artkonekt/concord/blob/master/src/Concord.php#L124
;)

public function user()
{
  return $this->hasOne(app('Custom/Module/Model'));
}

The above will work as you are resolving the dependency through the IOC, even if Custom/Module/Model is extended/overridden.

Yes, but the app('Custom/Module/Model') call makes a new surplus object every time.

Wouldn't the passed object be used if interacting with the relationship? Either way the relationship needs to make an instance of the object?

No, because eloquent creates new one(s) when fetches it/them from the db. Think about hasMany relations for example.

Or would the alternative to proxy's be to use Facades (as per the docs, it's exactly what you're trying to do)

https://laravel.com/docs/5.5/facades

Yes, I thought of that as well. The main difference is that facades are static resolvers to service objects (instances), but in this case we need a way to target classes. Plus you can't type hint facades. Also with facades all the time you'll have an object instance when you only need a string (actual class name)

Symfony projects achieve this with combining configuration and the service locator pattern. So if you need to know what is the class of 'product' you can return that from config 'product.class'.

You can do this with Laravel by using something like:
return $this->hasOne(config('product.class));

spatie/permissions is using this approach for example.

I wanted to avoid coding in config files.

Concord's approach was loosely inspired from Laravel Spark that has a useModel() method for overriding default models.

Thanks for the questions, it helped me to refresh my thoughts about this part of Concord;
I close this issue, but feel free to reopen if you have other questions/suggestion on this topic.