-
Notifications
You must be signed in to change notification settings - Fork 1
/
ListOrderBehavior.php
150 lines (135 loc) · 6.21 KB
/
ListOrderBehavior.php
1
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
/**
* Created by PhpStorm.
* User: Dragan Zivkovic <dzivkovic> <dragan.zivkovic.ts@gmail.com>
* Date: 20.6.13.
* Time: 19.28
*/
/**
* ListOrderBehavior class file.
*
* @author Dragan Zivkovic <dragan.zivkovic.ts@gmail.com>
*
*/
/**
* ListOrderBehavior will automatically fill models list_order field to next one or if list_order is
* already set it will update all records with larger list_order field to +1
* If $filterAttribute is not empty, Owner class will be filtered by filterAttribute(s)
*
* You may specify an active record model to use this behavior like so:
* <pre>
* public function behaviors(){
* return [
* 'ListOrderBehavior' => [
* 'class' => 'path.to.ListOrderBehavior',
* 'listOrderAttribute' => 'list_order_attributeName',
* 'filterAttributes' => 'filter attribute names COMMA separated',
* ]
* ];
* }
* </pre>
*
* @author Dragan Zivkovic <dragan.zivkovic.ts@gmail.com>
*/
class ListOrderBehavior extends CActiveRecordBehavior
{
/**
* actual field name that holds list order info
* @var string
*/
public $listOrderAttribute = 'list_order';
/**
* attribute name to filer owners class, if more than
* one separate them by COMMA
* @var null | string
*/
public $filterAttributes;
/**
* will hold models previous list_order
* add in model class
* @var integer
*/
public $currentListOrder;
public function beforeSave($event)
{
// if list_order is not set
if(!isset($this->owner->{$this->listOrderAttribute}) || $this->owner->{$this->listOrderAttribute} == '')
{
if(!isset($this->filterAttributes)){
// filters not set finding record with biggest list order
$biggest = call_user_func([get_class($this->owner), 'model'])->find(['order'=>$this->listOrderAttribute.' DESC']);
}else{
// filters are set forming array of filters
$filters = explode(',', $this->filterAttributes);
// initializing condition
$condition = '';
// populating condition
foreach($filters as $filter)
{
// trimming white space
$filter = trim($filter);
// adding filter to condition
if(is_null($this->owner->{$filter}))
$condition .= $filter .' IS NULL AND ';
else
$condition .= $filter . '=' . $this->owner->{$filter} .' AND ';
}
//removing last "AND"
$condition = substr($condition, 0, -4);
// finding record with biggest list_order, filtered by filters
$biggest = call_user_func([get_class($this->owner), 'model'])->find(['condition'=>$condition, 'order'=>$this->listOrderAttribute.' DESC']);
}
// record exist, owners list order is record->list_order + 1
if($biggest)
$nextOrder = $biggest->{$this->listOrderAttribute} + 1;
else
$nextOrder = 0; // no record found list_order is o
// setting owners list_order value
$this->owner->{$this->listOrderAttribute} = $nextOrder;
} else {// owners list order is set
// if list order is changed we need to update records with larger list_order
if($this->owner->{$this->listOrderAttribute} != $this->currentListOrder){
// filters are not set, finding all records with list_order >= than owners list_order
if(!isset($this->filterAttributes)){
$largerOrderRecords = call_user_func([get_class($this->owner), 'model'])->findAll(['condition'=>$this->listOrderAttribute.' >='.$this->owner->{$this->listOrderAttribute}]);
}else{
// filters are set, forming filter array
$filters = explode(',', $this->filterAttributes);
// initializing condition, list_order should be >= than owners list_order
$condition = $this->listOrderAttribute.' >='.$this->owner->{$this->listOrderAttribute}.' AND ';
foreach($filters as $filter)
{
// trimming white space
$filter = trim($filter);
// adding filter to condition
if(is_null($this->owner->{$filter}))
$condition .= $filter .' IS NULL AND ';
else
$condition .= $filter . '=' . $this->owner->{$filter} .' AND ';
}
// removing last "AND"
$condition = substr($condition, 0, -4);
// finding all records with list_order >= than owners list_order, filtered by filters
$largerOrderRecords = call_user_func([get_class($this->owner), 'model'])->findAll(['condition'=>$condition, 'order'=>'list_order ASC']);
}
// if there are records with bigger list order than owners list order
//using owners list order as start for updating larger ones
$no = $this->owner->{$this->listOrderAttribute} + 1;
if(!empty($largerOrderRecords))
{
foreach ($largerOrderRecords as $row)
{
$row->{$this->listOrderAttribute} = $no;
$row->save();
$no ++;
}
}
}
}
return parent::beforeSave($event);
}
public function afterFind($event){
$this->currentListOrder = $this->owner->{$this->listOrderAttribute};
return parent::afterFind($event);
}
}