Composer package - use custom model if exists - laravel

My apologies if this exists already but my search-fu can not find the answer.
I have a composer package, and want to use my model ONLY IF an existing model doesn't exist (or extend the custom model), but I can't seem to figure out how to specify the "use" command properly inside my composer model. Since I won't know the name of the "app" using the package, I can't extend it.
<?php
namespace MyComposer\Package\Models;
use Illuminate\Database\Eloquent\Model;
class MyPackageModel extends Model
{
If I put it as a config option, I can't use that in the extends i.e class MyPackageModel extends config('custom_model_name')
I had thought I should do the check in the ServiceProvider but I can't seem to find the right code to register the proper model name to use in there.
Thanks.

I've done something similar to this before, I believe. But my approach was slightly different. See if it makes sense:
Create a base class in your own package. This will be the fallback
model which will be used if the "local" package (the one consuming
your package) doesn't have it's own version of it;
Create a config file which states which model will be used. The default is the model inside your own package (i.e. the fallback);
After installing and setting up your package, if a user does nothing they will automatically have your base model available. If they wish to override your base model with a custom local version, they can simply extend your base model and alter the model to be used in their config file.
I've also found that sometimes it's useful for the base model to 1) implement an interface that can be checked in your package's logic without relying on a specific class (which, after all, is meant to be overridden, right?); and 2) have most of it's logic inside a trait which the "local" model can use without ever having to extend your model (crucial if the local model already extends some other class for whatever reason).
How you approach the code would very much depend what you plan to do with that model. Say, for example, you have a supporting class that creates media entries in your database. Here's your packages model:
<?php
namespace Namespace\Package;
class Media
{
//...
}
And here's the default config:
<?php
return [
'model' => \Namespace\Package\Media::class,
];
And here's a sample manipulation, where you actually account for the local app to override your own model:
<?php
namespace Namespace\Package;
class MediaManager
{
protected function getModel()
{
$model = config('package.model');
return new $model;
}
public function createMedia($attributes = [])
{
$media = $this->getModel($attributes);
$media->save();
return $media;
}
}
That is to say, you never reference any Media model literally. You do your manipulations via the MediaManager. Of course the logic is very simplistic, but hopefully it's enough to get the bigger picture.

Related

One To Many Polymorphic relationship - Call to undefined method getConnectionName()

I have followed the documentation very closely but something isn't working
https://laravel.com/docs/9.x/eloquent-relationships#one-to-many-polymorphic-relations
I am trying to add permissions into my code which will give a User access to a File or a Folder. I understand this needs a one-to-many polymorphic relationship as each Permission has one permissionable, while each File or Folder might have many permissions.
$table->morphs('permissionable'); in a migration adds the permissionable_type(string) and permissionable_id(integer) columns to the permissions table
The Permission model has been created with the relevant fillable columns and the permissionable method containing a morphTo():
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\File;
class Permission extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'user_id',
'permissionable_type',
'permissionable_id',
'privilege',
];
/**
* Get the parent object (file or folder).
*/
public function permissionable()
{
return $this->morphTo();
}
}
The Folder and File models have both had the following methods added:
public function permissions()
{
return $this->morphMany(Permission::class, 'permissionable');
}
A Permission is going to be created which will share a File with a User
And then the Permission is found and it's permissionable is requested
dd(Permission::find(1)->permissionable);
Except this is where the area happens:
I have tried to follow the documentation religiously and all the answers I see online just say to check namespace or ensure that all Models have an extends Model which I have already done.
Let me know if there is any more information I need to provide, thanks in advance.
i think you just changes model File class name, it's ok.
because this model's name conflict with Facades File class name
Thanks to Noah and Erik for their answers. You both helped me find the solution which was on the following site.
https://laracasts.com/discuss/channels/general-discussion/polymorphic-relations-gives-class-staff-not-found
The types need to include the paths in the database

Laravel: difference between using a Trait or extending a model

We're working on a Laravel application with a scheduling module. The module has three types of classes that can be put in an agenda: Task, Event and Department. We've therefore come up with the following class diagram:
Now, our question: if we were to realise this diagram, should we use a Trait or should we extend a Plannable model.
Plannable model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Plannable extends Model
{
// Code
}
Task model:
<?php
namespace App;
use App\Plannable;
class Task extends Plannable
{
// Code
}
Or should we use this as a trait:
Plannable trait:
<?php
namespace App\Traits;
trait Plannable
{
// Code
}
Task model:
<?php
namespace App;
use App\Plannable;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
use Plannable;
// Code
}
When you try to extend a class, means that "is a" relation, Car extends Vehicle, Car "is a" Vehicle. In your example, Task "is a" Plannable. Is it though?
On the other hand, traits use different approach, kinda like "Car uses wheels". In your example again, Task uses Plannable. Looks better than extending I guess?
Its hard to say more without understanding the which functions you will trait for this implementation. I hope, it gives some ideas.
Extending a parent/abstract class is best used when the models all share common characteristics but behave (function) in a unique way. For instance, Cars and Motorcycles are both Vehicles. They share common characteristics (e.g. headlights, indicators, engines, transmissions, etc.), but how to operate() them is unique from class to class.
Traits, on the other hand, are better used when the using classes (or Eloquent models in this case) require common functionality (i.e. methods) despite having different characteristics.
Without knowing more about your project, it seems like you're looking for the latter with each model having common functionality (perhaps addToCalendar(), reschedule(), etc.) despite having different characteristics.

Codeigniter Model extends CI_MODEL

I have a problem,
I want to create 2 different model extends CI_Model in core folder
for example
class MY_FirsModel extends CI_Model {
}
class MY_SecondModel extends CI_Model {
}
is it posible when using codeigniter
thank you
According to Codeigniter's Documentation, when extending a core class, you need to give the same name to your class, only changing CI_ by MY_.
When the loader class is fetching all core classes it looks for specific matching names such as Model, Controller, Exceptions and so on. It starts looking by the application/core folder, with prefixes MY_ and then goes to system/core if a extended class was not found.
If you need to maintain the names MY_FirsModel and MY_SecondModel, you can create these models in the application/libraries folder and the require these files in the classes you will use them.
require_once APPPATH.'libraries/MY_FirsModel.php';
and
require_once APPPATH.'libraries/MY_SecondModel.php';
it is possible to have it like that way. This will going to work. I read it once on CI forum (I don't remember the exact link as it's been long time) that some admins like to use this kind of style but many people are in favor of separating them into 2 different file

Yii2: Configurable models inside module

What is the best practice of including models/activerecords within a Yii2 module in a way that they are configurable?
These are just some of the problems we face when we want to use an activerecord included inside a module:
Adding events & behaviors to models/activerecords provided by a module. I want to attach events and behaviors to the models included in a module using Yii2's configuration format. How can this be done?
Defining relations with models/activerecords that exist outside of the module. When linking an activerecord contained inside a module to the User activerecord we can rely on Ỳii::$app->user->identityClass, but for other custom relations we might need to extend the activerecord. Is there any better approach? Extending activerecord classes from modules somewhat defeats the purpose of modularity.
Configuring various other variables within the module/activerecord. Let's say we want to adjust the max string length validation value. In a module Controller, we can always use $this->module->params to read any custom value, but we cannot do this from a Model or an ActiveRecord. What are we supposed to do instead?
I think you might end up using dependency injection:
Write an extension "\common\extensions\MyBootstrap":
namespace common\extensions;
use Yii;
use yii\base\BootstrapInterface;
use yii\base\Application;
class MyBootstrap implements BootstrapInterface {
/**
* #param Application $app Application
**/
public function bootstrap($app) {
Yii::$container->set("common\\modules\\test\\models\\Test1", "common\\modules\\test\\models\\Test2");
}
}
add to your config:
'bootstrap' => [
'common\extensions\MyBootstrap',
],
'components' => [
// ...
]
and in your code you have to use Yii::$container->get():
$test = Yii::$container->get('common\modules\test\models\Test1');
var_dump($test);
which will create Test2 model instead of Test1.
If you want this to happen for your ActiveRecord, override this:
public static function instantiate($row) {
return \Yii::$container->get(static::class);
}
EDIT: The underlying issue has now been resolved. We can use DI to inject relations into ActiveRecords.
As of July 2017, Yii2 does not allow ActiveRecord dependency injection!
See:
https://github.com/yiisoft/yii2/issues/8639
https://github.com/yiisoft/yii2/issues/11575
https://github.com/yiisoft/yii2/issues/5786
https://github.com/yiisoft/yii2/pull/14078
https://github.com/yiisoft/yii2/issues/13779
The only way around this is to configure your modules through your Yii::$app->params and then use those values inside module ARs (eg. when doing validation).

Namespacing and autoloading in Laravel

This might be a simple question but I'm wondering how do I autoload useful classes without declaring use statements on every single file.
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Input;
class HomeController extends Controller
{
public function index()
{
Input::get('query');
}
}
If I remove the use Illuminate\Support\Facades\Input; line I will get a class not found error because I'm using the Input class.
Is there a way to autoload useful classes like Input, Response, View like in Laravel 4. What's the point of the Aliases in app.php?
You can import input class using both:
use Illuminate\Support\Facades\Input;
or
use Input;
then you can use Input::get('query'); code. That's how PHP namespaces work - you can also look at How to use objects from other namespaces and how to import namespaces in PHP for more details about it.
If you don't use use statement for importing class, you can use \Input::get('query'); or \Illuminate\Support\Facades\Input::get('query');.
Aliases allow you not to use fully qualified classes for example \Illuminate\Support\Facades\Input but shorter form \Input. That's why I showed above 2 versions - the shorter one uses aliases and the longer uses full class path. The same mechanism is both in Laravel 4 and Laravel 5 I believe.
The problem is not really in Laravel, but in PHP. When you namespace a class, it assumes that everything inside that class will be in the same namespace, so you have to tell it that, for a particular class, you need it to use a different namespace.
You can use them by referring to the root namespace, like this:
class HomeController extends Controller
{
public function index()
{
\Input::get('query');
}
}

Resources