Laravel/Eloquet:致命错误:在非对象上调用成员函数connection()


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

我正在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并调用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;
    }
}

DB不可用的事实表明Eloquent没有被加载到顶部?

答案

使用服务提供商的boot方法引导程序包。


解释

既然您正在开发一个与Laravel一起使用的包,那么创建自己的Capsule实例是没有意义的。您可以直接使用Eloquent

您的问题似乎源于您的代码命中DB/Eloquent时尚未设置。

您还没有向我们展示您的服务提供商,但我猜您正在使用一个,并在register方法中完成所有操作。

由于您的程序包在执行之前依赖于要连接的不同服务提供商(DatabaseServiceProvider),因此引导程序包的正确位置是在服务提供商的boot方法中。

以下是文档中的一句话:

register方法在注册服务提供商时立即调用,而boot命令仅在路由请求之前调用。

因此,如果您的服务提供商中的操作依赖于另一个已经注册的服务提供商[…],则应该使用boot方法。

如果您使用Lumen,可能会出现相同的问题。在这种情况下,只需取消注释:

// $app->withFacades();
// $app->withEloquent();

bootstrap'app.php

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

我所做的很简单,我只是忘记在bootstrap/app.php中取消注释$app->withFacades(); $app->withEloquent();

现在工作良好

尝试包含DB facade以及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;

您必须使用

$capsule->`bootEloquent`();

database.php/中。

这是您的完整代码:

<?php
use Illuminate'Database'Capsule'Manager as Capsule;
$capsule = new Capsule;
$capsule->`addConnection`([
    'driver' => `'mysql'`,
    'host' => 'localhost',
    'database' => 'test1',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
    'collation' => 'utf8_general_ci',
    'prefix' => '',
]);
$capsule->`bootEloquent`();
<?php
namespace App'Providers;
use App'Setting;
use Illuminate'Support'ServiceProvider;
use Illuminate'Support'Facades'Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        Schema::defaultStringLength(191);

        $settings = Setting::all();
        foreach ($settings as $key => $settings) {
            if($key === 0) $system_name = $setting->value;
            elseif($key === 1) $favicon = $setting->value;
            elseif($key === 2) $front_logo = $setting->value;
            elseif($key === 3) $admin_logo = $setting->value;
        }
        $shareData = array(
            'system_name'=>$system_name,
            'favicon'=>$favicon,
            'front_logo'=>$front_logo,
            'admin_logo'=>$admin_logo
        );
        view()->share('shareData',$shareData);
    }
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}