web-dev-qa-db-ja.com

Laravel / Eloquent:致命的エラー:非オブジェクトのメンバー関数connection()の呼び出し

Laravel 4でパッケージを構築していますが、適切にインスタンス化されたオブジェクトのように見えるデータベースにアクセスしようとすると、オブジェクト以外のエラーが発生します。セットアップは次のとおりです。

問題の構成とクラス:

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"
        }  
    }
...

クラス:

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

}

呼び出し:

$message = new Message($msg);

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

エラー:

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

私は根本的な何かを失い、私の鼻の下にいると信じています。すべての助けてくれてありがとう!

編集:

ChatHistoryをインスタンス化し、書き込みを呼び出すクラスは次のとおりです。

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

DBが利用できないという事実は、Eloquentが一番上にロードされていないことを示唆していますか?

13
J. LaRosee

回答

サービスプロバイダーのbootメソッドでパッケージをブートストラップします。


説明

Laravelで使用するパッケージを開発しているので、独自のCapsuleインスタンスを作成しても意味がありません。 Eloquentを直接使用できます。

問題は、コードがヒットするまでにDB/Eloquentがまだセットアップされていないことに起因するようです。

あなたは私たちにあなたのサービスプロバイダーを示していませんが、私はあなたがそれを使っていて、registerメソッドでそれをすべてやっていると推測しています。

パッケージは別のサービスプロバイダー(DatabaseServiceProvider)に依存して実行されるので、bootstrapの正しい場所はサービスプロバイダーのbootメソッド。

ドキュメント からの引用です:

registerメソッドは、サービスプロバイダーが登録されるとすぐに呼び出されますが、bootコマンドは、リクエストがルーティングされる直前にのみ呼び出されます。

したがって、サービスプロバイダーのアクションが既に登録されている別のサービスプロバイダーに依存している場合は[...] bootメソッドを使用する必要があります。

26
Joseph Silber

Lumenを使用している場合、同じ問題が発生する可能性があります。この場合、コメントを外してください:

// $app->withFacades();

// $app->withEloquent();

bootstrap\app.php

15

@matpopと@TonyStarkは正しい軌道に乗っていました:Capsule\Managerは起動していませんでした。

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

起動後にEloquentを拡張できます。私は別の解決策が(テストされていない)の線に沿っているかもしれないと思う:

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

私がやったことは簡単で、bootstrap/app.phpで$app->withFacades(); $app->withEloquent();のコメントを外すのを忘れていました。

正常に動作するようになりました

2
afrikandev

DBファサードとEloquentを含めてみてください...

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

...そしてDB::table('chat_history')へのアクセス権があるかどうかを確認します。

(クラスでは、_use Illuminate\Database\Model;_への呼び出しは_Illuminate\Database\Eloquent\Model;_でなければなりません)

1
damiani