Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 713
J. LaRosee Avatar asked Oct 31 '14 17:10

J. LaRosee


2 Answers

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.

like image 156
Joseph Silber Avatar answered Oct 09 '22 23:10

Joseph Silber


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

like image 27
Kamil Szymański Avatar answered Oct 10 '22 00:10

Kamil Szymański