php - MySQL nested resources (pivot tables) permission to view/update/manage -
users                   transactions                    tasks +----+--------+         +----+---------------+          +----+--------+ | id |  name  |         | id |     name      |          | id |  name  | +----+--------+         +----+---------------+          +----+--------+ |  1 | user 1 |         |  1 | transaction 1 |          |  1 | task 1 | |  2 | user 2 |         |  2 | transaction 2 |          |  2 | task 2 | +----+--------+         +----+---------------+          +----+--------+   templates                   transaction_user                    task_transaction                   +----+---------------+      +---------+----------------+        +---------+----------------+       | id |     name      |      | user_id | transaction_id |        | task_id | transaction_id | +----+---------------+      +---------+----------------+        +---------+----------------+ |  1 | template 1    |      |       1 |              1 |        |       1 |              1 | |  2 | template 2    |      |       2 |              2 |        +---------+----------------+ +----+---------------+      +---------+----------------+               task_template +---------+-------------+ | task_id | template_id | +---------+-------------+ |       2 |           2 | +---------+-------------+   motive:  if there logged in user, user id 1, , he/she wants see task (say task id 1) want make sure task id 1 belongs to user before let him view it. need someway show user tasks belong him. task 1 model.. need handle models. have shared code below, trying hard?
i may have omitted details here please feel free ask questions. thanks.
code
<?php namespace someproject\repositories;  use user; use account; use task; use document; use transaction; use property; use db; use respond;  abstract class dbrepository {  /**  * many many relationships handeled using pivot tables  * use array figure out relationships ,  * particular resource's owner / account  */ public $pivot_models = array(      'task'          => array(                         'transaction'   => 'task_transaction'                     ),      'transaction'   => array(                         'user'  => 'transaction_user'                     ),      'document'      => array(                         'property'      => 'document_property',                         'task'          => 'document_task',                         'message'       => 'document_message'                     ) );  public $entity_ids;   public function getownersbyentity(array $ids, $entity)     {         $this->entity_ids = [];          $user_ids = [];           $entity = ucfirst(strtolower($entity)); // arrays keys case sensitive          if( $this->getpivotids($ids, $entity) )         {             foreach ($this->entity_ids $entity_name => $entity_ids_arr)             {                 $entity_name_lowercase = strtolower($entity_name);                  if($entity_name_lowercase != 'user')                 {                     $user_ids_from_entity = $entity_name::wherein('id', $entity_ids_arr)                                                 ->lists('user_id');                 }                 else                 {                     // have ids if entity user                     $user_ids_from_entity = $entity_ids_arr;                 }                  array_push($user_ids, $user_ids_from_entity);              }              $merged_user_ids = call_user_func_array('array_merge', $user_ids);              return array_unique($merged_user_ids);         }         else         {             return $entity::wherein('id', $ids)->lists('user_id');         }     }       public function getpivotids(array $ids, $entity)     {         $entity_lowercase = strtolower($entity);          if( array_key_exists($entity, $this->pivot_models) )         {             // pivot model              foreach ($this->pivot_models[$entity] $related_model => $table) // transaction, template             {                 $related_model_lowercase = strtolower($related_model);                  $this->entity_ids[$related_model] = db::table($table)                                                         ->wherein($entity_lowercase . '_id', $ids)                                                         ->lists($related_model_lowercase . '_id');                  if( $this->getpivotids($this->entity_ids[$related_model], $related_model) )                 {                     unset($this->entity_ids[$related_model]);                 }             }              return true;         }          return false;     } }      
to check if given model related one, want if right, need tiny method making of eloquent:
(implement in basemodel, entity or scope, whatever suits you)
// usage $task->isrelatedto('transactions.users', $id); // or $template->isrelatedto('tasks.transactions.users', auth::user());  // or kind of relation: // imagine this: user m-m transaction 1-m item m-1 group $group->isrelatedto('items.transaction.users', $id);   the magic happens here:
/**  * check if related given model through dot nested relations  *   * @param  string  $relations  * @param  int|\illuminate\database\eloquent\model  $id  * @return boolean  */ public function isrelatedto($relations, $id) {     $relations = explode('.', $relations);      if ($id instanceof model)     {         $related = $id;         $id = $related->getkey();     }     else     {         $related = $this->getnestedrelated($relations);     }      // recursive closure     $callback = function ($q) use (&$callback, &$relations, $related, $id)      {         if (count($relations))         {             $q->wherehas(array_shift($relations), $callback);         }         else         {             $q->where($related->getqualifiedkeyname(), $id);         }     };      return (bool) $this->wherehas(array_shift($relations), $callback)->find($this->getkey()); }  protected function getnestedrelated(array $relations) {     $models = [];      foreach ($relations $key => $relation)     {         $parent = ($key) ? $models[$key-1] : $this;         $models[] = $parent->{$relation}()->getrelated();     }      return end($models); }   hey, what's going on there?
isrelatedto() works this:
check if passed
$idmodel or id, , prepares$relatedmodel ,$iduse in callback. if don't pass object eloquent needs instantiate related models on$relations(relation1.relation2.relation3...) chain 1 interested in - that's happens ingetnestedrelated(), pretty straightforward.then need this:
// assuming relations 'relation1.relation2.relation3' $this->wherehas('relation1', function ($q) use ($id) { $q->wherehas('relation2', function ($q) use ($id) { $q->wherehas('relation3', function ($q) use ($id) { $q->where('id', $id); }); }); })->find($this->getkey()); // returns new instance of current model or null, cast (bool)since don't know how relation nested, need use recurrency. pass closure
wherehas, need use little trick in order call inside body (in fact don't call it, rather pass$callbackwherehasmethod, since latter expects closure 2nd param) - this might useful unfamiliar anonymous recursive php functions:// save variable , pass reference $callback = function () use (&$callback) { if (...) // call $callback again else // finish; }we pass closure
$relations(as array now) reference in order unshift elements, , when got them (meaning nestedwherehas), putwhereclause instead ofwherehas, search our$relatedmodel.finally let's return
bool
Comments
Post a Comment