31

Is it possible to call a Laravel model by string?

This is what i'm trying to achieve but its failing:

$model_name = 'User';
$model_name::where('id', $id)->first();

I get the following exception:

exception 'ErrorException' with message 'Undefined variable: User'
Parampal Pooni
  • 2,958
  • 8
  • 34
  • 40

6 Answers6

72

Yes, you can do this, but you need to use the fully qualified class name:

$model_name = 'App\Model\User';
$model_name::where('id', $id)->first();

If your model name is stored in something other than a plain variable (e.g. a object attribute), you will need to use an intermediate variable in order to get this to work.

$model = $this->model_name;
$model::where('id', $id)->first();
patricus
  • 59,488
  • 15
  • 143
  • 145
28

Try this:

$model_name = 'User';
$model = app("App\Model\{$model_name}");
$model->where('id', $id)->first();
Emeka Mbah
  • 16,745
  • 10
  • 77
  • 96
  • 5
    Can you explain why you used app() ? Thanks in advance – Raja Khoury Oct 03 '18 at 00:07
  • 1
    @RajaKhoury to get instance, or in other words "return var_dump( app('App\User') );" and see result – Vit May 27 '20 at 13:09
  • 1
    I had to escape the trailing backslash with another backslash: `$modelPath = "App\Models\\{$modelName}";` – Luke Jun 11 '22 at 15:32
  • This was exactly what I needed, next time all you have to do is give a detailed description of exactly what your code is expected to do, some of us run code in our heads before we start typing. – 3m1n3nc3 Jul 29 '22 at 00:54
2

This method should work well:

private function getNamespace($model){
    $dirs = glob('../app/Models/*/*');

    return array_map(function ($dir) use ($model) {
        if (strpos($dir, $model)) {
            return ucfirst(str_replace(
                '/',
                '\\',
                str_replace(['../', '.php'], '', $dir)
            ));
        }
    }, array_filter($dirs, function ($dir) use ($model) {
        return strpos($dir, $model);
    }));
}

My project has multiple subdirectory and this function work well. So I recover the namespace of the model with $model = current($this->getNamespace($this->request->get('model'))); Then I just have to call my query: $model::all()

itepifanio
  • 572
  • 5
  • 16
1

if you use it in many of the places use this function

function convertVariableToModelName($modelName='',$nameSpace='App')
        {
            if (empty($nameSpace) || is_null($nameSpace) || $nameSpace === "") 
            {                
               $modelNameWithNameSpace = "App".'\\'.$modelName;
                return app($modelNameWithNameSpace);    
            }

            if (is_array($nameSpace)) 
            {
                $nameSpace = implode('\\', $nameSpace);
                $modelNameWithNameSpace = $nameSpace.'\\'.$modelName;
                return app($modelNameWithNameSpace);    
            }elseif (!is_array($nameSpace)) 
            {
                $modelNameWithNameSpace = $nameSpace.'\\'.$modelName;
                return app($modelNameWithNameSpace);    
            }
        }

Example if you want to get all the user

Scenario 1:

 $userModel= convertVariableToModelName('User');
  $result = $userModel::all();

Scenario 2:

if your model in in custom namespace may be App\Models

$userModel= convertVariableToModelName('User',['App','Models']);
$result = $userModel::all();

Hope it helps

ManojKiran A
  • 5,896
  • 4
  • 30
  • 43
0

Yes you can do it with more flexible way. Create a common function.

function getWhere($yourModel, $select, $is_model_full_path=null, $condition_arr=null)
{
    if(!$is_model_full_path){ // if your model exist in App directory
        $yourModel ="App\\$yourModel";
    }
    if(!$condition_arr){
        return $yourModel::all($select)->toArray();
    }
    return $App_models_yourModel::all($select)->where($condition_arr)->toArray();
}

Now you can call this method in different ways.

getWhere('User', ['id', 'name']); // with default path of model
getWhere('App\Models\User', ['id', 'name'], true); // with custom path of model
getWhere('User', ['id', 'name'], false, ['id', 1]); // with condition array

By the way I like to use such functions.

scopchanov
  • 7,966
  • 10
  • 40
  • 68
Zia
  • 213
  • 1
  • 8
0

You can also try like this:-

use App\Model\User;

class UsersController extends Controller
{

 protected $model;

 public function __construct(User $model)
 {
    $this->model = $model;
 }

 public function getUser()
 {
  $data = $this->model->where('id', $id)->first();

  return $data;
 }

}
Sheetal Mehra
  • 478
  • 3
  • 13