2017-07-18 107 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" 
    ] 
]);