当前位置: 动力学知识库 > 问答 > 编程问答 >

php - Cast Laravel query results to class

问题描述:

When creating a query using the syntax DB::table('foo'), it creates a generic class (stdClass). Is there any way to cast the resulting rows to a specific class?

Here is some example code that should explain what I want to do:

$result = DB::table('foo')->get();

$converted = (Foo) $result; // Not going to work

I want to cast all the (stdClass) objects of the array to the Foo class.

网友答案:

Yes, you can hydrate the results into the classes you want. I found the answer buried deep in a mess of half-answers and confused questions that make up the terrible Laracasts.com forum. Thanks for asking the question here instead of there.

Once you get the results, hydrate them using your model class:

$result = DB::table('foo')->get();
$converted = Foo::hydrate($result);

Edit: Found some documentation on the hydrate method too, if that helps

Edit 2: I found myself in a situation where I needed to cast results from either an array or a collection, depending on the results of a query. When a collection was returned, it was correctly hydrated, but when the result was an array, they were just stdClass. I wrote a quick method added to my master model that took a collection of arrays or objects, or a pagination object, and correctly cast it to the object I wanted.

网友答案:

Typically you'd achieve this by setting the PDO Statement fetch_style to PDO::FETCH_CLASS as below

$statement->fetchAll(PDO::FETCH_CLASS, "App\User");

If you look at the method Illuminate\Database\Connection::select you'll see that whilst you can set the fetch_style/fetchMode, you can not the second argument.

public function select($query, $bindings = array(), $useReadPdo = true)
{
    return $this->run($query, $bindings, function($me, $query, $bindings) use ($useReadPdo)
    {
        if ($me->pretending()) return array();

        // For select statements, we'll simply execute the query and return an array
        // of the database result set. Each element in the array will be a single
        // row from the database table, and will either be an array or objects.
        $statement = $this->getPdoForSelect($useReadPdo)->prepare($query);

        $statement->execute($me->prepareBindings($bindings));

        return $statement->fetchAll($me->getFetchMode());
    });
}

Nor can you get access to the statement before fetchAll is called to call PDOStatement::setFetchMode for example.

You could perhaps attempt to extend Illuminate\Database\Connection and utilise that throughout other Database related classes by extending and replacing where necessary but it seems like a hefty task to maintain.

The other option is to use Eloquent which will give you classes back of a particular type but you get the slight additional overhead of hydrating the model objects.

class Foo extends Illuminate\Database\Eloquent\Model {
    protected $table = 'foo';
}

Foo::all()
Foo::where('col', 1)->get()
网友答案:

You cannot type cast it this way.
You can build change Your Foo class to get handle of object and work with it.

class Foo {
  private $object = null;
  public function __construct(stdClass $object) {
    $this->object = $object;
  }

  public function __get($property) {
    if (property_exists($this->object, $property)) {
      return $this->object->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this->object, $property)) {
      $this->object->$property = $value;
    }
    return $this;
  }

  public static function make(stdClass $object) {
    return new self($object);
  }

  public static function makeCollection(array $collection) {
    foreach($collection AS $key => $Item) {
      $collection[$key] = self::make($Item);
    }
    return $collection;
  }
}

$result = DB::table('foo')->get();
$converted = Foo::makeCollection($result);
网友答案:

Yes. For example:

  $query = DB::table('example_tbl')->where('id', $id)->get();
  $cast = (array)$query;
  var_dump($cast);
分享给朋友:
您可能感兴趣的文章:
随机阅读: