2017-07-18 110 views
0

我一直在尝试无数个小时,但在更新模型关系时仍然存在问题,最接近的是“方法填充不存在”。错误。Laravel 5无法更新关系

上市型号:

class Listing extends Model 
    {  
     protected $fillable = [ 
      'uid', 'start_date',........... 
     ];  

     public function locations() 
     { 
      return $this->hasMany('App\ListingLocation'); 
     }   
    } 

位置(关系到上市 - 的hasMany):

class ListingLocation extends Model 
{ 

    protected $fillable = [ 
     'listing_id', 'location', 
    ]; 

    public function listing() 
    { 
     return $this->belongsTo('App\Listing'); 
    } 
} 

这将返回我的模型和关系,我可以用DD($上市)查看

$listing = Listing::with('locations')->findOrFail($id); 

这将更新我的列表模型,我可以在再次调用dd($ listing)后看到更改

$listing->fill($array); 

但是,当我试图按照下面的关系填充关系时,我得到'方法填充不存在'。

$listing->locations->fill($array['locations']); 

如何在调用$ listing-> push();之前成功地更新关系?

+0

'Locations'是一个'hasMany'关系,所以它会返回一个集合,而不是一个单一的模型。你必须选择一个位置来更新。 – aynber

+0

我想你正在寻找同步方法:'$ listing-> locations() - > sync($ array ['locations']);' –

+0

由于这是一对多的关系,所以同步无法正常工作?当调用同步时,我得到一个错误:调用未定义的方法Illuminate \\ Database \\ Query \\ Builder :: sync() – DLO

回答

2

更改您的位置,以一个单一的记录,不是一个集合

例如:

$listings->locations->first()->fill($array['locations']); 

填写每个记录使用的foreach

@foreach($listings->locations as $location) 
$location->fill(do_something); 
@endforeach 
+0

这似乎并不奏效,因为它试图填充第一个记录中的位置数组。即使我将它更新为.....-> fill($ array ['locations'] [0]);它仍然不会更新属性时做一个转储和死 – DLO

+0

还注意到如果我使用更新而不是填充,这项工作,但我想覆盖该模型的所有位置,而不仅仅是第一个。同步似乎是我想要但不知道它与一对多的关系 – DLO

+0

我更新了我的答案,同步适用于多对多......不是一对多 – derrysan7

0

我结束了创建一个新的类延伸hasMany让我使用同步按照alexweissman在https://laracasts.com/discuss/channels/general-discussion/syncing-one-to-many-relationships。从论坛

提取物:

use Illuminate\Database\Eloquent\Relations\HasMany; 

/** 
* @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/HasMany.php 
*/ 
class HasManySyncable extends HasMany 
{ 
    public function sync($data, $deleting = true) 
    { 
     $changes = [ 
      'created' => [], 'deleted' => [], 'updated' => [], 
     ]; 

     $relatedKeyName = $this->related->getKeyName(); 

     // First we need to attach any of the associated models that are not currently 
     // in the child entity table. We'll spin through the given IDs, checking to see 
     // if they exist in the array of current ones, and if not we will insert. 
     $current = $this->newQuery()->pluck(
      $relatedKeyName 
     )->all(); 

     // Separate the submitted data into "update" and "new" 
     $updateRows = []; 
     $newRows = []; 
     foreach ($data as $row) { 
      // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and 
      // match a related row in the database. 
      if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) { 
       $id = $row[$relatedKeyName]; 
       $updateRows[$id] = $row; 
      } else { 
       $newRows[] = $row; 
      } 
     } 

     // Next, we'll determine the rows in the database that aren't in the "update" list. 
     // These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id'). 
     $updateIds = array_keys($updateRows); 
     $deleteIds = []; 
     foreach ($current as $currentId) { 
      if (!in_array($currentId, $updateIds)) { 
       $deleteIds[] = $currentId; 
      } 
     } 

     // Delete any non-matching rows 
     if ($deleting && count($deleteIds) > 0) { 
      $this->getRelated()->destroy($deleteIds); 

      $changes['deleted'] = $this->castKeys($deleteIds); 
     } 

     // Update the updatable rows 
     foreach ($updateRows as $id => $row) { 
      $this->getRelated()->where($relatedKeyName, $id) 
       ->update($row); 
     } 

     $changes['updated'] = $this->castKeys($updateIds); 

     // Insert the new rows 
     $newIds = []; 
     foreach ($newRows as $row) { 
      $newModel = $this->create($row); 
      $newIds[] = $newModel->$relatedKeyName; 
     } 

     $changes['created'][] = $this->castKeys($newIds); 

     return $changes; 
    } 


    /** 
    * Cast the given keys to integers if they are numeric and string otherwise. 
    * 
    * @param array $keys 
    * @return array 
    */ 
    protected function castKeys(array $keys) 
    { 
     return (array) array_map(function ($v) { 
      return $this->castKey($v); 
     }, $keys); 
    } 

    /** 
    * Cast the given key to an integer if it is numeric. 
    * 
    * @param mixed $key 
    * @return mixed 
    */ 
    protected function castKey($key) 
    { 
     return is_numeric($key) ? (int) $key : (string) $key; 
    } 
} 

然后,您可以覆盖你的模型类雄辩的的hasMany方法:

/** 
    * Overrides the default Eloquent hasMany relationship to return a HasManySyncable. 
    * 
    * {@inheritDoc} 
    */ 
    public function hasMany($related, $foreignKey = null, $localKey = null) 
    { 
     $instance = $this->newRelatedInstance($related); 

     $foreignKey = $foreignKey ?: $this->getForeignKey(); 

     $localKey = $localKey ?: $this->getKeyName(); 

     return new HasManySyncable(
      $instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey 
     ); 
    } 

    /** 
    * Get all of a user's phone numbers. 
    */ 
    public function phones() 
    { 
     return $this->hasMany('App\Phone'); 
    } 

的同步方法现在将提供给你对这个模型任何的hasMany关系:

$user->phones()->sync([ 
    [ 
    'id' => 21, 
     'label' => "primary", 
     'number' => "5555551212" 
    ], 
    [ 
    'id' => null, 
     'label' => "mobile", 
     'number' => "1112223333" 
    ] 
]);