Php 拉威尔与关系
我正在制作一个调查网站,用户可以从0到10提供答案。 我在试验类型转换将所有问题和答案存储在一行中 这是数据库中“分数”字段的外观Php 拉威尔与关系,php,arrays,laravel,Php,Arrays,Laravel,我正在制作一个调查网站,用户可以从0到10提供答案。 我在试验类型转换将所有问题和答案存储在一行中 这是数据库中“分数”字段的外观 {"5":8,"6":8} 这是意料之中的。“5”和“6”是问题的ID,8是用户提供的分数 我想知道是否有可能询问答案,但包括与问题的关系。我希望看到以下结果 {"5" => {"question: ...", "answer: ..."} 所以我的问题是:是否有可能对数组施放,但在Laravel中包含关系?或者我需要循环数组并获取每行的问题数据 谢谢大家
{"5":8,"6":8}
这是意料之中的。“5”和“6”是问题的ID,8是用户提供的分数
我想知道是否有可能询问答案,但包括与问题的关系。我希望看到以下结果
{"5" => {"question: ...", "answer: ..."}
所以我的问题是:是否有可能对数组施放,但在Laravel中包含关系?或者我需要循环数组并获取每行的问题数据
谢谢大家! 您可以使用自定义访问器和变异器执行任何操作,但我不建议将关系存储在数据库中。您不希望在其中引用可能独立更改的整个对象,因此请将其保留为ids,并在从db获取分数后装饰输出
public function getScoresAttribute($value)
{
// if using casts to array, this should already be done
$scores = json_decode($value, true);
$questions = Question::whereIn('id', array_keys($scores))->get();
$rs = [];
$questions->each(function($q) use ($rs, $scores) {
$rs[$q->id] = [
'question' => $q->toArray(),
'answer' => $scores[$q->id],
];
});
return $rs;
}
现在,您可以执行以下操作:
dd($survey->scores);
你会得到修饰过的数据。@Robert你的答案是我以前的解决方案。现在,我有了一个新的解决方案!这是我的答案 我们需要为Foo模型创建一个新特性。首先在laravel的“应用”文件夹下创建“关系”和“关系”文件夹。“关系”文件夹位于“关系”文件夹内 这个答案只是支持一维数组关系。您可以编辑此“完美…”
<?php
namespace App\Models;
use App\Relations\HasBarRelations;
use Illuminate\Database\Eloquent\Model;
use App\Models\Bar;
class Foo extends Model
{
use HasBarRelations; // Trait
protected $table = "foo";
protected $fillable = ["bar"];
protected $casts = [
"bar" => "array" // Array cast
];
public function bar()
{
return $this->belongsToBar(Bar::class, "id", "bar"); // Relationship
}
}
“app/Relations/Relations”最后,这是完整的文件夹路径结构
这是“app/Models/Foo.php”模型文件源。
<?php
namespace App\Models;
use App\Relations\HasBarRelations;
use Illuminate\Database\Eloquent\Model;
use App\Models\Bar;
class Foo extends Model
{
use HasBarRelations; // Trait
protected $table = "foo";
protected $fillable = ["bar"];
protected $casts = [
"bar" => "array" // Array cast
];
public function bar()
{
return $this->belongsToBar(Bar::class, "id", "bar"); // Relationship
}
}
我认为这是不可能的。我认为您应该遍历数组并使用
Question::find($id)
。
<?php
namespace App\Relations\Relation;
use Closure;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class BarRelation extends Relation
{
/**
* The baseConstraints callback
*
* @var string
*/
protected $foreignKey;
protected $localKey;
/**
* Create a new belongs to relationship instance.
*
* @param Builder $query
* @param Model $parent
* @param string $foreignKey
* @param $localKey
*/
public function __construct(Builder $query, Model $parent, $foreignKey, $localKey)
{
$this->foreignKey = $foreignKey;
$this->localKey = $localKey;
parent::__construct($query, $parent);
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
if (static::$constraints) {
$this->query->where($this->foreignKey, '=', $this->getParentKey());
$this->query->whereNotNull($this->foreignKey);
}
}
/**
* Get the key value of the parent's local key.
*
* @return mixed
*/
public function getParentKey()
{
return $this->parent->getAttribute($this->localKey);
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
$key = $this->related->getTable().'.'.$this->foreignKey;
$whereIn = $this->whereInMethod($this->related, $this->foreignKey);
$this->query->{$whereIn}($key, $this->getEagerModelKeys($models));
}
/**
* Gather the keys from an array of related models.
*
* @param array $models
* @return array
*/
protected function getEagerModelKeys(array $models)
{
$keys = [];
// First we need to gather all of the keys from the parent models so we know what
// to query for via the eager loading query. We will add them to an array then
// execute a "where in" statement to gather up all of those related records.
foreach ($models as $model) {
if (is_array($model->{$this->localKey}) && count($model->{$this->localKey}) > 0) {
foreach($model->{$this->localKey} as $ids){
$keys[] = $ids;
}
}
}
// If there are no keys that were not null we will just return an array with null
// so this query wont fail plus returns zero results, which should be what the
// developer expects to happen in this situation. Otherwise we'll sort them.
if (count($keys) === 0) {
return [null];
}
sort($keys);
return array_values(array_unique($keys));
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $this->matchOneOrMany($models, $results, $relation, 'one');
}
/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$foreign = $this->foreignKey;
return $results->mapToDictionary(function ($result) use ($foreign) {
return [$result->{$foreign} => $result];
})->all();
}
protected function getRelationValue(array $dictionary, $key, $type)
{
$value = $dictionary[$key];
return $type === 'one' ? reset($value) : $this->related->newCollection($value);
}
protected function matchOneOrMany(array $models, Collection $results, $relation, $type)
{
$dictionary = $this->buildDictionary($results);
if(count($dictionary) > 0){
$data = [];
foreach ($models as $model) {
foreach($model->getAttribute($this->localKey) as $key){
if (array_key_exists($key, $dictionary)) {
$data[] = $this->getRelationValue($dictionary, $key, $type);
$model->setRelation(
$relation, collect(array_unique($data))
);
}
}
}
}
return $models;
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
return $this->get();
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return Collection
*/
public function get($columns = ['*'])
{
// First we'll add the proper select columns onto the query so it is run with
// the proper columns. Then, we will get the results and hydrate out pivot
// models with the result of those columns as a separate model relation.
$columns = $this->query->getQuery()->columns ? [] : $columns;
if ($columns == ['*']) {
$columns = [$this->related->getTable().'.*'];
}
$builder = $this->query->applyScopes();
$models = $builder->addSelect($columns)->getModels();
// If we actually found models we will also eager load any relationships that
// have been specified as needing to be eager loaded. This will solve the
// n + 1 query problem for the developer and also increase performance.
if (count($models) > 0) {
$models = $builder->eagerLoadRelations($models);
}
return $this->related->newCollection($models);
}
}
$foo = Foo::with(["bar"])->where("id", 1)->first();
$bars = $foo->bar(); // Result is the Eloquent Collection!
$bar = $bars->first(); // Bar::class