Content sharing / object access

Intro

MAX trebuie sa ofere posibilitatea de a partaja/share-ui/da acces la anumite resurse, de la o companie la alta. De exemplu trebuie sa putem defini campuri custom pe o firma, si sa dam acces la ele altei firme. Caz concret: cand avem francize definim campurile pe firma mama si dam acces la ele francizelor. La fel, pentru documentele uploadate.

Cum functioneaza

Indiferent de ce obiecte sunt share-uite, setarile de share se salveaza in acelasi loc: tabela object_access. Pentru fiecare obiect exista un tip: itemType. Pana acum avem:

  • ITEMTYPE_UPLOADED_DOCUMENT pentru documente incarcate
  • ITEMTYPE_CUSTOM_FIELD pentru campuri custom
  • ITEMTYPE_PARTNER pentru parteneri

Exista trei moduri de a partaja obiecte:

  • RECEIVERTYPE_ALL_MINE : obiectul este partajat catre toate companiile la care am access
  • RECEIVERTYPE_ALL_TREE : obiectul este partajat catre toate companiile din arbore – in aval (adica in jos pe arbore) indiferent daca am sau nu acces la ele
  • RECEIVERTYPE_COMPANIES : obiectul este partajat numai catre companiile specificate de mine (si salvate in object_access.receiverId, cate una pe linie)

UI

In UI, trebuie sa putem seta partea de share-ing per obiect. Adica in exemplul nostru, per camp custom. Asta inseamna ca:

  1. in formularul de cam custom trebuie sa apara input-urile specifice pentru share
  2. in listing-ul de campuri custom ar fi frumos sa si vedem catre cine este share-uit acel camp
  3. tot in listing-ul de campuri custom ar trebuie sa vedem si campurile care au fost share-uite catre compania mea (si pe care sa nu le pot edita sau sterge)
  4. peste tot pe unde folosesc campul (factura, partener, etc) trebuie – evident – sa pot folosi si campurile share-uite catre mine

Pasi

Pentru a face asta trebuie sa urmam cativa pasi (modificarile de mai jos se fac in modelul/view-ul/etc al obiectului care trebuie sa poata fi partajat)

  1. creeam o constanta ITEMTYPE_XXX pentru tipul nostru de obiect pe care vrem sa il partajam.
  2. in model trebuie sa avem doua atribute noi. Pe acestea se bazeaza sistemul de object access/sharing.
// the following two parameters are used to provide
// share settings for the custom field, saved in the
// object_access table
public $receiverType;
public $receiverIds;

2. tot in model, trebuie sa apara in RULES ca safe:

[[....,'receiverType','receiverIds'], 'safe']

3. si de asemenea setam captions:

public function attributeLabels() {
  return [
    'id'             => Yii::t('app', 'ID'),
    ....
    'receiverType'   => Yii::t('app', 'Share to'),
    'receiverIds'    => Yii::t('app', 'Specific companies'),
  ];
}

3′ si iar, in getItemTypes()

static function getItemTypes() {
  return [
    self::ITEMTYPE_UPLOADED_DOCUMENT        => Yii::t("app", "Uploaded document"),
    self::ITEMTYPE_CUSTOM_FIELD             => Yii::t("app", "Custom field"),
    self::ITEMTYPE_PARTNER                  => Yii::t("app", "Partner"),
    self::ITEMTYPE_CUSTOM_REPORT            => Yii::t("app", "Custom report"),
    self::ITEMTYPE_UPLOADED_DOCUMENT_FOLDER => Yii::t("app", "Uploaded document folder"),
  ];
}

3”. si in functia care returneaza numele obiectelor, pentru lista cu obiecte partajate:

function sharedObject() {
  $ret = "?";
  switch ($this->itemType){
    case self::ITEMTYPE_UPLOADED_DOCUMENT:
      $object = UploadedDocument::find()->where(["=","id",$this->itemId])->one();
      if(is_object($object)) {
        $pi = pathinfo($object->fap);
        $ret = $pi['basename'];
      }
      break;
    case self::ITEMTYPE_CUSTOM_FIELD:
      $object = CustomField::find()->where(["=","id",$this->itemId])->one();
      $ret = is_object($object) ? $object->name : "-";
      break;
    case self::ITEMTYPE_PARTNER:
      $object = Partner::find()->where(["=","id",$this->itemId])->one();
      $ret = is_object($object) ? $object->name : "-";
      break;
    case self::ITEMTYPE_CUSTOM_REPORT:
      $object = CustomReport::find()->where(["=","id",$this->itemId])->one();
      $ret = is_object($object) ? $object->name : "-";
      break;
    case self::ITEMTYPE_UPLOADED_DOCUMENT_FOLDER:
      $object = UploadedDocumentFolder::find()->where(["=","id",$this->itemId])->one();
      $ret = is_object($object) ? $object->name : "-";
      break;
  }

  return $ret;
}

4. tot in model, in afterSave la sfarsit. Aceast apel va face salvarea propriu-zisa a setarilor de share.

ObjectAccess::saveAccessSettings(ObjectAccess::ITEMTYPE_XXX, $this->id, $this->receiverType, $this->receiverIds);

5. in view-ul formei. In acest fel incarcam input-urile care se ocupa de share in formular.

<div class="row  padding-20 border-top-dashed<?= ($layout == 'popup' ?' hide' :'') ?>">
  <?=Yii::$app->controller->renderPartial('/layouts/object-access-form',['model'=>$model,'form'=>$form])?>
</div>

6. in actionEdit(), imediat dupa findModel() . Ca sa se incarce setarile de share la edit.

if($id>0){
  ObjectAccess::loadAccessSettings($model,ObjectAccess::ITEMTYPE_XXX);
}

7. in index.php. Ca sa putem afisa setarile de share in listing-ul obiectelor.

'sharing'     => [
  'attribute'     => 'settings',
  'options'       => ['class' => ' '],
  'label'         => Yii::t("app", "Access"),
  'filter'        => FALSE,
  'format'        => 'raw',
  'filterOptions' => ['class' => 'empty'],
  'value'         => function ($model) {
    return ObjectAccess::getNiceCaption(ObjectAccess::ITEMTYPE_XXX,$model->id);
  }],

si la fiecare buton trebuie sa nu permitem afisarea daca obiectul nu este al nostru; de exemplu :

'update'    => function ($url, $model, $key) {
  return $model->companyId!=Company::currentId() ? '' : Html::a('<i class="icon md-edit btn btn-pure color-primary"></i>',
    ['edit', 'id' => $model->id],
    ['data-tooltip'        => 'true',
     'data-original-title' => Yii::t('app', 'Update')]
  );
},

8. in search model. Ca sa afisam si obiectele care au fost share-uite cu firma curenta.

$query->andWhere(["=","companyId",$this->companyId])->orWhere(['in','id',ObjectAccess::getSharedObjects(ObjectAccess::ITEMTYPE_XXX)]);

9. in modelul in care se folosesc (de ex pentru custom fields – in invoice, partner si contract) – ca sa fie incarcate si cele share-uite

public function init() {
  $this->autoloadSharedCustomFields = ObjectAccess::ITEMTYPE_XXX;
  ......
  parent::init();
}

10. acolo unde sunt folosite, trebuie adaugat – cel mai probabil :

orWhere("in" , "campulRespectivDeId" , ObjectAccess::getSharedObjects( ... ));

ca sa fie incarcate si campurile shared.

Complicat !

About

Software Development Manager, Architect

Leave a Reply

Your email address will not be published. Required fields are marked *

[TOP]