Laravel/Eloquent: Fatal error: Call to a member function connection() on a non-object

48,506

Solution 1

Answer:

Bootstrap your package in your service provider's boot method.


Explanation:

Since you're developing a package to be used with Laravel, there's no point in making your own Capsule instance. You can just use Eloquent directly.

Your problem seems to stem from DB/Eloquent not being set up yet by the time your code hits it.

You have not shown us your service provider, but I'm guessing you're using one and doing it all in the register method.

Since your package depends on a different service provider (DatabaseServiceProvider) to be wired up prior to its own execution, the correct place to bootstrap your package is in your service provider's boot method.

Here's a quote from the docs:

The register method is called immediately when the service provider is registered, while the boot command is only called right before a request is routed.

So, if actions in your service provider rely on another service provider already being registered [...] you should use the boot method.

Solution 2

In case you're working with Lumen, you may occur identical problem. In this case just uncomment:

// $app->withFacades();

// $app->withEloquent();

in bootstrap\app.php

Solution 3

@matpop and @TonyStark were on the right track: Capsule\Manager wasn't being booted.

use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;
$capsule->addConnection([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'project',
    'username'  => 'root',
    'password'  => '',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
]);

// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;

$capsule->setEventDispatcher(new Dispatcher(new Container));

// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();

// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();

I am able to extend Eloquent after booting. I think another solution might be along the lines of (but not tested):

include __DIR__ . '/../../vendor/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/start.php';
$app->boot();

Solution 4

What i did was simple, i just forgot to uncomment $app->withFacades(); $app->withEloquent(); in my bootstrap/app.php.

Now works fine

Solution 5

Try including the DB facade as well as Eloquent...

use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Model as Eloquent;

...and then see if you have access to DB::table('chat_history').

(Also note that in your class, your call to use Illuminate\Database\Model; should be Illuminate\Database\Eloquent\Model; )

Share:
48,506
J. LaRosee
Author by

J. LaRosee

I live in Seattle. Awesome.

Updated on January 25, 2022

Comments

  • J. LaRosee
    J. LaRosee over 2 years

    I'm building a package in Laravel 4 but am getting a non-object error when attempting to access the db from which seems to be a properly instantiated object. Here's the setup:

    The config and class in question:

    composer.json:

    ...
    "autoload": {
            "classmap": [
                "app/commands",
                "app/controllers",
                "app/models",
                "app/database/migrations",
                "app/database/seeds",
                "app/tests/TestCase.php"
            ],
            "psr-0": {
                "Vendor\\Chat": "src/vendor/chat/src"
            }  
        }
    ...
    

    The class:

    namespace Vendor\Chat;
    
    use Illuminate\Database\Eloquent\Model as Eloquent;
    
    
    class ChatHistory extends Eloquent
    {
        protected $table = 'chat_history';
    
        protected $fillable = array('message', 'user_id', 'room_token');
    
        public function __construct($attributes = array())
        {
            parent::__construct($attributes);
        }
    
    }
    

    The call:

    $message = new Message($msg);
    
    $history = new ChatHistory;
    $history->create(array(
                     'room_token' => $message->getRoomToken(),
                     'user_id' => $message->getUserId(),
                     'message' => $message->getMessage(),
                  ));
    

    The error:

    PHP Fatal error:  Call to a member function connection() on a non-object in /home/vagrant/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 2894
    

    I believe I'm missing something fundamental and under my nose. Thanks for any and all help!

    EDIT:

    Here is the class that's instantiating ChatHistory and calling the write:

    namespace Vendor\Chat;
    
    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;
    
    use Vendor\Chat\Client;
    use Vendor\Chat\Message;
    use Vendor\Chat\ChatHistory;
    
    use Illuminate\Database\Model;
    
    class Chat implements MessageComponentInterface {
    
        protected $app;
    
        protected $clients;
    
        public function __construct() 
        {
            $this->clients = new \SplObjectStorage;
        }
    
        public function onOpen(ConnectionInterface $conn) 
        {
            $client = new Client;
            $client->setId($conn->resourceId);
            $client->setSocket($conn);
    
            $this->clients->attach($client);
        }
    
        public function onMessage(ConnectionInterface $conn, $msg) 
        {
            $message = new Message($msg);
    
            $history = new ChatHistory;
            ChatHistory::create(array(
                         'room_token' => $message->getRoomToken(),
                         'user_id' => $message->getUserId(),
                         'message' => $message->getMessage(),
                      ));
            /* error here */
            /* ... */ 
        }
    
        public function onClose(ConnectionInterface $conn) 
        {
            $this->clients->detach($conn);
        }
    
        public function onError(ConnectionInterface $conn, \Exception $e) 
        {
            $conn->close();
        }
    
        protected function getClientByConn(ConnectionInterface $conn)
        {
            foreach($this->clients as $client) {
                if($client->getSocket() === $conn) {
                    return $client;
                } 
            } 
    
            return null;
        }
    }
    

    The fact that DB isn't available suggest that Eloquent isn't being loaded up top?

  • matpop
    matpop over 9 years
    Are you developing a stand-alone package which uses Eloquent or are you building a package that's specifically intended for use with Laravel?
  • J. LaRosee
    J. LaRosee over 9 years
    It's a package that's specific for Laravel.
  • J. LaRosee
    J. LaRosee over 9 years
    @matpop Your suggestion got me onto the right track so I'd like to give you the bounty. Not sure how to go about that, given you've not provided an answer.
  • matpop
    matpop over 9 years
    Thank you for your appreciation, it's worth much more than SO rep so don't worry about it. Actually, at this stage I think no one yet deserves the bounty, cause it seems you fixed the problem with Capsule for now, and I believe it's not the best way for a package specific for Laravel. If all is setup correctly, the service providers of such packages are loaded by the underlying Laravel app after the "normal" service providers are already booted (including the DatabaseServiceProvider), so you shouldn't need Capsule nor explicitly call $app->boot() (which is already called).
  • matpop
    matpop over 9 years
    Have you followed the official guide? Sorry if I won't be there for a while, my timezone is at the other side of the ocean :)
  • damiani
    damiani over 9 years
    @matpop, that's what I was wondering. If this is a Laravel package, using Capsule (even if it gets the code to work) shouldn't be necessary and is masking some other problem. @J.LaRosee, what happens if you include use Illuminate\Support\Facades\DB; and try to access the DB object, i.e. DB::table('chat_history')?
  • matpop
    matpop over 9 years
    Here goes the bounty! I did guess we were just missing some statement in the docs... always read it carefully!
  • J. LaRosee
    J. LaRosee over 9 years
    Employing the Capsule "fixed" the issue but it appears to be a less-than-optimal solution (github.com/illuminate/database). Looking to bootstrap the package is what I was looking for, looks like, though the Capsule solution helped get me on the right path by showing me that the code isn't the issue, the order in which I was loading and using code was incorrect.
  • Admin
    Admin over 7 years
    This fixed it for me, but this is for Lumen.
  • azurecorn
    azurecorn about 4 years
    Just the case :) Thanks a lot.
  • Stephen Ostermiller
    Stephen Ostermiller about 2 years
    A code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.