web-dev-qa-db-fra.com

Laravel / Eloquent: Erreur fatale: appel à une connexion de fonction membre () sur un non-objet

Je construis un package dans Laravel 4 mais j'obtiens une erreur non liée à un objet lorsque j'essaie d'accéder à la base de données qui semble être un objet correctement instancié. Voici la configuration:

La config et la classe en 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"
        }  
    }
...

La classe:

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);
    }

}

L'appel:

$message = new Message($msg);

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

L'erreur:

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

Je crois que je manque quelque chose de fondamental et sous mon nez. Merci pour toute aide!

ÉDITER:

Voici la classe qui instancie ChatHistory et appelle l'écriture:

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;
    }
}

Le fait que DB ne soit pas disponible suggère qu'Eloquent n'est pas chargé en haut?

13
J. LaRosee

Réponse :

Amorcez votre package dans la méthode boot de votre fournisseur de services.


Explication :

Puisque vous développez un package à utiliser avec Laravel, il est inutile de créer votre propre instance Capsule. Vous pouvez simplement utiliser Eloquent directement.

Votre problème semble provenir du fait que DB/Eloquent n'est pas encore configuré au moment où votre code le frappe.

Vous ne nous avez pas montré votre fournisseur de services, mais je suppose que vous en utilisez un et que vous faites tout cela dans la méthode register.

Étant donné que votre package dépend d'un fournisseur de services différent (DatabaseServiceProvider) à câbler avant sa propre exécution, l'emplacement correct pour bootstrap votre package est dans la méthode boot de votre fournisseur de services.

Voici une citation de les docs :

La méthode register est appelée immédiatement lorsque le fournisseur de services est enregistré, tandis que la commande boot est uniquement appelée juste avant le routage d'une demande.

Par conséquent, si les actions de votre fournisseur de services reposent sur un autre fournisseur de services déjà enregistré, [...] vous devez utiliser la méthode boot.

26
Joseph Silber

Si vous travaillez avec Lumen, vous pouvez rencontrer un problème identique. Dans ce cas, décommentez simplement:

// $app->withFacades();

// $app->withEloquent();

dans bootstrap\app.php

15
Kamil Szymański

@matpop et @TonyStark étaient sur la bonne voie: Capsule\Manager n'était pas en cours de démarrage.

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();

Je peux étendre Eloquent après le démarrage. Je pense qu'une autre solution pourrait aller dans le sens (mais non testée):

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

Ce que j'ai fait était simple, j'ai juste oublié de décommenter $app->withFacades(); $app->withEloquent(); dans mon bootstrap/app.php.

Fonctionne maintenant bien

2
afrikandev

Essayez d'inclure la façade DB ainsi que Eloquent ...

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

... puis voyez si vous avez accès à DB::table('chat_history').

(Notez également que dans votre classe, votre appel à use Illuminate\Database\Model; Devrait être Illuminate\Database\Eloquent\Model;)

1
damiani