mongodb / laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)
https://www.mongodb.com/docs/drivers/php/laravel-mongodb/
MIT License
7.01k stars 1.43k forks source link

Call to a member function prepare() on null #2223

Open djeux opened 3 years ago

djeux commented 3 years ago

Description:

Adding a mysql relation to a mongodb model causes the given error when fetching the relation.

{
  "exception": "Error"
  "file": "/var/www/project/vendor/laravel/framework/src/Illuminate/Database/Connection.php"
  "line": 338
  "message": "Call to a member function prepare() on null"
}

My model class

use App\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Jenssegers\Mongodb\Eloquent\Model;

class Draft extends Model
{
    protected $collection = 'survey_drafts';

    protected $connection = 'mongodb';

    protected $attributes = [
        'questions' => [],
    ];

    public function owner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'owner_id', 'id');
    }
}

The User class uses the default MySQL connection.

Upon investigation further, I saw that Connection::getPdoForSelect is being called on the MongoDB connection instance, where the $pdo is NULL. Therefore throwing the error when trying to retrieve the PDO class for some reason.

The cause for this is that the MySQL User model does not have a $connection property defined as it should pick the default mysql connection when it's not specifically defined otherwise (as its done with the mongodb model).

This is being done in HasRelationships::newRelatedInstance(). When being used as a relation to a mongodb model the $this->connection is a mongodb connection.

The only way to fix this currently is to add a

$connection = 'mysql'

to all MySQL models that are being used as relations to a mongodb model. In the given example, to the User model

djeux commented 3 years ago

The drawback to this "fix" is that if you're using the memory database for tests, they will start to fail as the models will be using the mysql connection instead of the memory one, as it's hardcoded into them.

jalallinux commented 3 years ago

i think this is the used models of installed packages

vahidei commented 2 years ago

same issue

Mahan-Shoghy commented 1 year ago

I have the same issue too

Cart Class

use Jenssegers\Mongodb\Eloquent\Model;

class Cart extends Model
{
    protected $connection = 'mongodb';

    protected $guarded = [];

    protected $with = ['items'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function items()
    {
        return $this->hasMany(CartItem::class);
    }
}

User model is default mysql connection and when I call like this: $cart->user

I got same error: Call to a member function prepare() on null

But in reverse works well with HybridRelations $user->carts

alkhachatryan commented 1 year ago

I have the same issue without any relation with a simple model

class ActivityLog extends Model
{
    protected $connection = 'mongodb';
    protected $fillable = [
        'action'
    ];
}
shahid163 commented 11 months ago

Replace Illuminate\Database\Eloquent\Model with MongoDB\Laravel\Eloquent\Model inside your models. Example:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;    // instead of Illuminate\Database\Eloquent\Model

class Comment extends Model
{

}

using mongodb/laravel-mongodb

prodevuk commented 5 months ago
  • Laravel-mongodb Version: 3.8.2
  • PHP Version: 7.4.13
  • Database Driver & Version: 1.9.0

Description:

Adding a mysql relation to a mongodb model causes the given error when fetching the relation.

{
  "exception": "Error"
  "file": "/var/www/project/vendor/laravel/framework/src/Illuminate/Database/Connection.php"
  "line": 338
  "message": "Call to a member function prepare() on null"
}

My model class

use App\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Jenssegers\Mongodb\Eloquent\Model;

class Draft extends Model
{
    protected $collection = 'survey_drafts';

    protected $connection = 'mongodb';

    protected $attributes = [
        'questions' => [],
    ];

    public function owner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'owner_id', 'id');
    }
}

The User class uses the default MySQL connection.

Upon investigation further, I saw that Connection::getPdoForSelect is being called on the MongoDB connection instance, where the $pdo is NULL. Therefore throwing the error when trying to retrieve the PDO class for some reason.

The cause for this is that the MySQL User model does not have a $connection property defined as it should pick the default mysql connection when it's not specifically defined otherwise (as its done with the mongodb model).

This is being done in HasRelationships::newRelatedInstance(). When being used as a relation to a mongodb model the $this->connection is a mongodb connection.

The only way to fix this currently is to add a

$connection = 'mysql'

to all MySQL models that are being used as relations to a mongodb model. In the given example, to the User model

I think this is a logical fix. Only issue I have here is if you have 100s of models then it eliminates your model portability. Another solution could be to store connection names as constants and use those in your models so you can mass assign later in the future.

mayankagrawal809 commented 1 week ago

I would suggest you to run php artisan queue:listen or If running with supervisor php artisan queue:work --once

This will bootstrap the application everytime a new job is processed, :work will cache some things between each jobs.