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