1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
36:
37: class RelationshipsBehavior extends CActiveRecordBehavior {
38:
39: protected $_relationships;
40: protected $_visibleRelatedX2Models;
41: protected $_relatedX2Models;
42:
43: public function getRelationships($refreshCache = false) {
44: if ($refreshCache || !isset($this->_relationships)) {
45: $this->_relationships =
46: Relationships::model()->findAll($this->getAllRelationshipsCriteria());
47: }
48: return $this->_relationships;
49: }
50:
51: public function createRelationship($target, $firstLabel = null, $secondLabel = null) {
52: if ($this->isValidTarget($target)) {
53: $relationship = new Relationships();
54: $relationship->firstType = get_class($this->owner);
55: $relationship->firstId = $this->owner->id;
56: $relationship->firstLabel = $firstLabel;
57: $relationship->secondType = get_class($target);
58: $relationship->secondId = $target->id;
59: $relationship->secondLabel = $secondLabel;
60: if ($relationship->save()) {
61: return true;
62: }else{
63: return $relationship->getAllErrorMessages();
64: }
65: }
66: return false;
67: }
68:
69: public function deleteRelationship(CActiveRecord $target) {
70: $affected = 0;
71: if ($this->hasRelationship($target)) {
72: $affected+=Relationships::model()->deleteAllByAttributes(array(
73: 'firstType' => get_class($this->owner),
74: 'firstId' => $this->owner->id,
75: 'secondType' => get_class($target),
76: 'secondId' => $target->id,
77: ));
78: $affected+=Relationships::model()->deleteAllByAttributes(array(
79: 'firstType' => get_class($target),
80: 'firstId' => $target->id,
81: 'secondType' => get_class($this->owner),
82: 'secondId' => $this->owner->id,
83: ));
84: }
85: return $affected;
86: }
87:
88: public function getRelationship(CActiveRecord $target) {
89: $rel1 = Relationships::model()->findByAttributes(array(
90: 'firstType' => get_class($this->owner),
91: 'firstId' => $this->owner->id,
92: 'secondType' => get_class($target),
93: 'secondId' => $target->id,
94: ));
95: if(isset($rel1)){
96: return $rel1;
97: }
98:
99: $rel2 = Relationships::model()->findByAttributes(array(
100: 'firstType' => get_class($target),
101: 'firstId' => $target->id,
102: 'secondType' => get_class($this->owner),
103: 'secondId' => $this->owner->id,
104: ));
105: if(isset($rel2)){
106: return $rel2;
107: }
108: return null;
109: }
110:
111: public function getRelationshipLabel(CActiveRecord $target) {
112: $relationship = $this->getRelationship($target);
113: if ($relationship->firstType == get_class($this->owner) &&
114: $relationship->firstId == $this->owner->id) {
115: return $relationship->firstLabel;
116: }
117: return $relationship->secondLabel;
118: }
119:
120: public function getRelatedX2Models($refreshCache = false) {
121: if (!isset($this->_relatedX2Models) || $refreshCache) {
122: $myModelName = get_class($this->owner);
123: $this->_relatedX2Models = array();
124: $relationships = $this->getRelationships($refreshCache);
125: $modelRelationships = array();
126: foreach ($relationships as $relationship) {
127: list($idAttr, $typeAttr) = ($relationship->firstId == $this->owner->id &&
128: $relationship->firstType == $myModelName) ?
129: array('secondId', 'secondType') :
130: array('firstId', 'firstType');
131: if (!array_key_exists($relationship->$typeAttr,
132: $modelRelationships))
133: $modelRelationships[$relationship->$typeAttr] = array();
134: if (!empty($relationship->$idAttr))
135: $modelRelationships[$relationship->$typeAttr][] = $relationship->$idAttr;
136: }
137: foreach ($modelRelationships as $modelName => $ids) {
138: $this->_relatedX2Models = array_merge(
139: $this->_relatedX2Models,
140: X2Model::model($modelName)->findAllByPk($ids));
141: }
142: }
143: return $this->_relatedX2Models;
144: }
145:
146: public function getVisibleRelatedX2Models($refreshCache = false) {
147: if (!isset($this->_visibleRelatedX2Models) || $refreshCache) {
148: if (Yii::app()->params->isAdmin) {
149: $this->_visibleRelatedX2Models = $this->getRelatedX2Models($refreshCache);
150: } else {
151: $this->_visibleRelatedX2Models = array_filter($this->getRelatedX2Models($refreshCache),
152: function ($model) {
153: return Yii::app()->controller->checkPermissions($model, 'view');
154: }
155: );
156: }
157: }
158: return $this->_visibleRelatedX2Models;
159: }
160:
161: public function afterSave($event){
162: $oldAttributes = $this->owner->getOldAttributes();
163: $linkFields = Fields::model()->findAllByAttributes(array(
164: 'modelName'=>get_class($this->owner),
165: 'type'=>'link',
166: ));
167: foreach($linkFields as $field){
168: $nameAndId = Fields::nameAndId($this->owner->getAttribute($field->fieldName));
169: $oldNameAndId = Fields::nameAndId(
170: isset($oldAttributes[$field->fieldName])
171: ? $oldAttributes[$field->fieldName] : '');
172: if(!empty($oldNameAndId[1]) && $nameAndId[1] !== $oldNameAndId[1]){
173: $oldTarget = X2Model::model($field->linkType)->findByPk($oldNameAndId[1]);
174: $this->owner->deleteRelationship($oldTarget);
175: }
176: $newTarget = X2Model::model($field->linkType)->findByPk($nameAndId[1]);
177: $this->owner->createRelationship($newTarget);
178: }
179: parent::afterSave($event);
180: }
181:
182: public function afterDelete($event) {
183: $condition = '(`firstType`=:ft AND `firstId`=:fid) OR (`secondType`=:st AND `secondId`=:sid)';
184: Relationships::model()->deleteAll($condition,
185: array(
186: ':ft' => get_class($this->owner),
187: ':fid' => $this->owner->id,
188: ':st' => get_class($this->owner),
189: ':sid' => $this->owner->id
190: )
191: );
192: parent::afterDelete($event);
193: }
194:
195: public function isValidTarget($target) {
196: if (!$target instanceof CActiveRecord) {
197: return false;
198: }else if (!$target->asa('relationships')) {
199: return false;
200: } else if (empty($target->id)) {
201: return false;
202: } else if (get_class($this->owner) === get_class($target)
203: && $this->owner->id === $target->id){
204: return false;
205: }else if ($this->hasRelationship($target)) {
206: return false;
207: }
208: return true;
209: }
210:
211: public function hasRelationship($target) {
212: $rel1 = Relationships::model()->countByAttributes(array(
213: 'firstType' => get_class($this->owner),
214: 'firstId' => $this->owner->id,
215: 'secondType' => get_class($target),
216: 'secondId' => $target->id,
217: ));
218:
219: $rel2 = Relationships::model()->countByAttributes(array(
220: 'firstType' => get_class($target),
221: 'firstId' => $target->id,
222: 'secondType' => get_class($this->owner),
223: 'secondId' => $this->owner->id,
224: ));
225:
226: return ($rel1 || $rel2);
227: }
228:
229: private function getAllRelationshipsCriteria() {
230: return new CDbCriteria(array(
231: 'condition' =>
232: '(firstType=:myType AND firstId=:myId OR
233: secondType=:myType AND secondId=:myId) AND
234: (firstId IS NOT NULL AND firstId != "" AND
235: secondId IS NOT NULL AND secondId != "")',
236: 'params' => array(
237: ':myType' => get_class($this->owner),
238: ':myId' => $this->owner->id,
239: )
240: ));
241: }
242:
243: protected function getVisibleRelationshipsCriteria() {
244: $criteria = new CDbCriteria;
245: $qpg = new QueryParamGenerator(':getRelationshipsCriteria');
246: $models = $this->getVisibleRelatedX2Models();
247: if (!count($models)) {
248: $criteria->addCondition('FALSE');
249: } else {
250: foreach ($models as $model) {
251: $criteria->addCondition(
252: "(firstType=:myType AND firstId=:myId AND
253: secondType={$qpg->nextParam(get_class($model))} AND
254: secondId={$qpg->nextParam($model->id)})", 'OR');
255: $criteria->addCondition(
256: "(secondType=:myType AND secondId=:myId AND
257: firstType={$qpg->nextParam(get_class($model))} AND
258: firstId={$qpg->nextParam($model->id)})", 'OR');
259: }
260: $criteria->params = array_merge(
261: array(
262: ':myType' => get_class($this->owner),
263: ':myId' => $this->owner->id,
264: ), $qpg->getParams());
265: }
266: return $criteria;
267: }
268:
269: }
270: