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:
- in formularul de cam custom trebuie sa apara input-urile specifice pentru share
- in listing-ul de campuri custom ar fi frumos sa si vedem catre cine este share-uit acel camp
- 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)
- 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)
- creeam o constanta ITEMTYPE_XXX pentru tipul nostru de obiect pe care vrem sa il partajam.
- 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 !