namespace Illuminate\Database\Eloquent\Relations;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
// yesterday we just say this belongsTo
// today we just use this belongToMany
class BelongsToMany extends Relation
{// Belongs To Many just a relation
/**
* The intermediate table for the relation.
*
* @var string
*/
protected $table; // the middle table , ha ha
// intermediate: like middle ,
// this is the intermediate table for the relation
/**
* The foreign key of the parent model.
*
* @var string
*/
protected $foreignKey;// The foreign key of the parent model.
/**
* The associated key of the relation.
*
* @var string
*/
protected $otherKey;// the relation key: like the associated key of the relation
/**
* The "name" of the relationship.
*
* @var string
*/
protected $relationName;//The "name" of the relationship.
/**
* The pivot table columns to retrieve.
*
* @var array
*/
protected $pivotColumns = [];//The pivot table columns to the retrieve
// retrieve like: search,
// this is main table columns to be search, or retrieve.
/**
* Any pivot table restrictions.
*
* @var array
*/
protected $pivotWheres = [];// Any pivot table restrictions.
// a pivot table array store about this be restrictions.
/**
* The custom pivot table column for the created_at timestamp.
*
* @var string
*/
protected $pivotCreatedAt;// The custom pivot table column for the create_at timestamp.
//The custom pivot table column
// just for the created_at timestamp
/**
* The custom pivot table column for the updated_at timestamp.
*
* @var string
*/
protected $pivotUpdatedAt;
// The custom pivot table column
// for updated_at timestamp.
/**
* Create a new belongs to many relationship instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Model $parent
* @param string $table
* @param string $foreignKey
* @param string $otherKey
* @param string $relationName
* @return void
*/
public function __construct(Builder $query, Model $parent, $table, $foreignKey, $otherKey, $relationName = null)
{//Create a new belongs to many relationship instance.
$this->table = $table;// set table
$this->otherKey = $otherKey;// set the other Key
$this->foreignKey = $foreignKey;//set foreignKey
$this->relationName = $relationName;//set relationName
parent::__construct($query, $parent);// use parent construct function
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
return $this->get();
}// Get the result of the relationship.
// just a get result
/**
* Set a where clause for a pivot table column.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
{//Set a where clause for a pivot table column.
$this->pivotWheres[] = func_get_args();// this pivotWheres get args
return $this->where($this->table.'.'.$column, $operator, $value, $boolean);
}// just where
/**
* Set an or where clause for a pivot table column.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function orWherePivot($column, $operator = null, $value = null)
{
return $this->wherePivot($column, $operator, $value, 'or');
}// set clause in or where
// just a wrap function with the wherePivot
/**
* Execute the query and get the first result.
*
* @param array $columns
* @return mixed
*/
public function first($columns = ['*'])
{
$results = $this->take(1)->get($columns);// get the first result
return count($results) > 0 ? $results->first() : null;// get the first result
}//execute like fire: the query and get the first result.
/**
* Execute the query and get the first result or throw an exception.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|static
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function firstOrFail($columns = ['*'])
{// first or fail
if (! is_null($model = $this->first($columns))) {
return $model;
}// has this first result ,just return it
// other throw new exception
throw new ModelNotFoundException;
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get($columns = ['*'])
{// Execute the query as a "select" statement.
// 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;
//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.
$select = $this->getSelectColumns($columns);// get the select columns
$builder = $this->query->applyScopes();// apply Scopes ,fire to builder
$models = $builder->addSelect($select)->getModels();// get models
$this->hydratePivotRelation($models);// hydrate Pivot Relation
// 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);
}//loader other developer
return $this->related->newCollection($models);// make a new collection
}
/**
* Get a paginator for the "select" statement.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{//Get a paginator for the "select" statement.
$this->query->addSelect($this->getSelectColumns($columns));
// add select columns for this query
$paginator = $this->query->paginate($perPage, $columns, $pageName, $page);
// set the paginate
$this->hydratePivotRelation($paginator->items());
// hydrate Pivot Relation
return $paginator;
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @return \Illuminate\Contracts\Pagination\Paginator
*/
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page')
{//Paginate the given query into a simple paginator.
$this->query->addSelect($this->getSelectColumns($columns));
// set select
$paginator = $this->query->simplePaginate($perPage, $columns, $pageName);
// get the simple Paginate
$this->hydratePivotRelation($paginator->items());
// hydrate Relation the result
return $paginator;
}//return result
/**
* Chunk the results of the query.
*
* @param int $count
* @param callable $callback
* @return bool
*/
public function chunk($count, callable $callback)
{//Chunk the results of the query.
$this->query->addSelect($this->getSelectColumns());
// query addSelect get Select Columns
return $this->query->chunk($count, function ($results) use ($callback) {
$this->hydratePivotRelation($results->all());
return $callback($results);
});// return the chunk
}
/**
* Hydrate the pivot table relationship on the models.
*
* @param array $models
* @return void
*/
protected function hydratePivotRelation(array $models)
{//Hydrate the pivot table relationship on the models.
// To hydrate the pivot relationship, we will just gather the pivot attributes
// and create a new Pivot model, which is basically a dynamic model that we
// will set the attributes, table, and connections on so it they be used.
foreach ($models as $model) {
$pivot = $this->newExistingPivot($this->cleanPivotAttributes($model));
$model->setRelation('pivot', $pivot);
}// loop this models
// and set the pivot about this model
}