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:

  1. check if passed $id model or id, , prepares $related model , $id use in callback. if don't pass object eloquent needs instantiate related models on $relations (relation1.relation2.relation3...) chain 1 interested in - that's happens in getnestedrelated(), pretty straightforward.

  2. 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) 
  3. 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 $callback wherehas method, 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; } 
  4. we pass closure $relations (as array now) reference in order unshift elements, , when got them (meaning nested wherehas), put where clause instead of wherehas, search our $related model.

  5. finally let's return bool


Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

Python ctypes access violation with const pointer arguments -