1515use \yii \helpers \Inflector ;
1616use \yii \helpers \StringHelper ;
1717
18- trait RelationTrait {
18+ trait RelationTrait
19+ {
1920
20- public function loadAll ($ POST ) {
21+ public function loadAll ($ POST )
22+ {
2123 if ($ this ->load ($ POST )) {
2224 $ shortName = StringHelper::basename (get_class ($ this ));
2325 foreach ($ POST as $ key => $ value ) {
@@ -31,28 +33,28 @@ public function loadAll($POST) {
3133 $ relModelClass = $ rel ->modelClass ;
3234 $ relPKAttr = $ relModelClass ::primaryKey ();
3335 $ isManyMany = count ($ relPKAttr ) > 1 ;
34- if ($ isManyMany ){
35- foreach ($ value as $ relPost ){
36- if (!empty (array_filter ($ relPost ))){
36+ if ($ isManyMany ) {
37+ foreach ($ value as $ relPost ) {
38+ if (!empty (array_filter ($ relPost ))) {
3739 $ condition = [];
3840 $ condition [$ this ->primaryKey ()[0 ]] = $ this ->primaryKey ;
39- foreach ($ relPost as $ relAttr => $ relAttrVal ){
40- if (in_array ($ relAttr , $ relPKAttr ))
41+ foreach ($ relPost as $ relAttr => $ relAttrVal ) {
42+ if (in_array ($ relAttr , $ relPKAttr ))
4143 $ condition [$ relAttr ] = $ relAttrVal ;
4244 }
4345 $ relObj = $ relModelClass ::findOne ($ condition );
44- if (is_null ($ relObj )){
46+ if (is_null ($ relObj )) {
4547 $ relObj = new $ relModelClass ;
4648 }
4749 $ relObj ->load ($ relPost , '' );
4850 $ container [] = $ relObj ;
4951 }
5052 }
5153 $ this ->populateRelation ($ relName , $ container );
52- }else if ($ isHasMany ) {
54+ } else if ($ isHasMany ) {
5355 $ container = [];
5456 foreach ($ value as $ relPost ) {
55- if (!empty (array_filter ($ relPost ))) {
57+ if (!empty (array_filter ($ relPost ))) {
5658 /* @var $relObj ActiveRecord */
5759 $ relObj = (empty ($ relPost [$ relPKAttr [0 ]])) ? new $ relModelClass : $ relModelClass ::findOne ($ relPost [$ relPKAttr [0 ]]);
5860 $ relObj ->load ($ relPost , '' );
@@ -73,82 +75,140 @@ public function loadAll($POST) {
7375 }
7476 }
7577
76- public function saveAll () {
78+ public function saveAll ()
79+ {
7780 /* @var $this ActiveRecord */
7881 $ db = $ this ->getDb ();
7982 $ trans = $ db ->beginTransaction ();
8083 try {
8184 if ($ this ->save ()) {
8285 $ error = 0 ;
83- if (!empty ($ this ->relatedRecords )){
86+ if (!empty ($ this ->relatedRecords )) {
8487 foreach ($ this ->relatedRecords as $ name => $ records ) {
85- if (!empty ($ records )){
88+ if (!empty ($ records )) {
89+ $ isHasMany = is_array ($ records );
8690 $ AQ = $ this ->getRelation ($ name );
8791 $ link = $ AQ ->link ;
8892 $ notDeletedPK = [];
8993 $ relPKAttr = $ records [0 ]->primaryKey ();
90- $ isCompositePK = (count ($ relPKAttr ) > 1 );
91- /* @var $relModel ActiveRecord */
92- foreach ($ records as $ index => $ relModel ) {
93- $ notDeletedFK = [];
94- foreach ($ link as $ key => $ value ) {
95- $ relModel ->$ key = $ this ->$ value ;
96- $ notDeletedFK [$ key ] = "$ key = ' {$ this ->$ value }' " ;
97- }
98- $ relSave = $ relModel ->save ();
99- if (!$ relSave || !empty ($ relModel ->errors )) {
100- $ relModelWords = Inflector::camel2words (StringHelper::basename ($ AQ ->modelClass ));
101- $ index ++;
102- foreach ($ relModel ->errors as $ validation ) {
103- foreach ($ validation as $ errorMsg ) {
104- $ this ->addError ($ name , "$ relModelWords # $ index : $ errorMsg " );
105- }
94+ $ isManyMany = (count ($ relPKAttr ) > 1 );
95+ if ($ isHasMany ) {
96+ /* @var $relModel ActiveRecord */
97+ $ i = 0 ;
98+ foreach ($ records as $ index => $ relModel ) {
99+ $ notDeletedFK = [];
100+ foreach ($ link as $ key => $ value ) {
101+ $ relModel ->$ key = $ this ->$ value ;
102+ if ($ isManyMany ) $ notDeletedFK [$ key ] = $ this ->$ value ;
103+ elseif ($ isHasMany ) $ notDeletedFK [$ key ] = "$ key = ' {$ this ->$ value }' " ;
106104 }
107- $ error = 1 ;
108- } else {
109- //GET PK OF REL MODEL
110- if ($ isCompositePK ) {
111- foreach ($ relModel ->primaryKey as $ attr => $ value ) {
112- $ notDeletedPK [$ attr ][] = "' $ value' " ;
105+ $ relSave = $ relModel ->save ();
106+
107+ if (!$ relSave || !empty ($ relModel ->errors )) {
108+ $ relModelWords = Inflector::camel2words (StringHelper::basename ($ AQ ->modelClass ));
109+ $ index ++;
110+ foreach ($ relModel ->errors as $ validation ) {
111+ foreach ($ validation as $ errorMsg ) {
112+ $ this ->addError ($ name , "$ relModelWords # $ index : $ errorMsg " );
113+ }
113114 }
115+ $ error = 1 ;
114116 } else {
115- $ notDeletedPK [] = "' $ relModel ->primaryKey ' " ;
117+ //GET PK OF REL MODEL
118+ if ($ isManyMany ) {
119+ foreach ($ relModel ->primaryKey as $ attr => $ value ) {
120+ $ notDeletedPK [$ i ][$ attr ] = "' $ value' " ;
121+ $ fields [$ attr ] = "" ;
122+ }
123+ } else {
124+ $ notDeletedPK [] = "' $ relModel ->primaryKey ' " ;
125+ }
116126 }
127+ $ i ++;
117128 }
118- }
119- if (!$ this ->isNewRecord ) {
120- //DELETE WITH 'NOT IN' PK MODEL & REL MODEL
121- $ notDeletedFK = implode (' AND ' , $ notDeletedFK );
122- if ($ isCompositePK ) {
123- echo "composite pk \n" ;
124- $ compiledNotDeletedPK = [];
125- foreach ($ notDeletedPK as $ attr => $ pks ) {
126- $ compiledNotDeletedPK [$ attr ] = "$ attr NOT IN( " . implode (', ' , $ pks ) . ") " ;
127- if (!empty ($ compiledNotDeletedPK [$ attr ])) {
128- $ relModel ->deleteAll ("$ notDeletedFK AND " . implode (' AND ' , $ compiledNotDeletedPK ));
129+ if (!$ this ->isNewRecord ) {
130+ //DELETE WITH 'NOT IN' PK MODEL & REL MODEL
131+ if ($ isManyMany ) {
132+ // echo "composite pk\n";
133+ // echo "not deleted PK : \n";
134+ // print_r($notDeletedPK);
135+ // echo "not deleted FK : \n";
136+ // print_r($notDeletedFK);
137+ // echo "\nfields : \n";
138+ // print_r($fields) . "\n";
139+ $ contoh = ['and ' ,['actor_id ' => 1 ],['not in ' , new \yii \db \Expression ('(actor_id, film_id) ' ),
140+ [
141+ new \yii \db \Expression ('(1,1) ' ),
142+ new \yii \db \Expression ('(1,23) ' ),
143+ new \yii \db \Expression ('(1,25) ' ),
144+ new \yii \db \Expression ('(1,980) ' ),
145+ new \yii \db \Expression ('(1,970) ' ),
146+ new \yii \db \Expression ('(1,939) ' )
147+ ]]];
148+ // echo $relModel::find()->where(['and',['actor_id' => 1],['not in', new \yii\db\Expression('(actor_id, film_id)'),
149+ // [
150+ // new \yii\db\Expression('(1,1)'),
151+ // new \yii\db\Expression('(1,23)'),
152+ // new \yii\db\Expression('(1,25)'),
153+ // new \yii\db\Expression('(1,980)'),
154+ // new \yii\db\Expression('(1,970)'),
155+ // new \yii\db\Expression('(1,939)')
156+ // ]]])->createCommand()->rawSql;
157+ $ compiledFields = implode (", " , array_keys ($ fields ));
158+ $ compiledNotDeletedPK = ['and ' ,$ notDeletedFK ];
159+ $ notIn = ['not in ' , new \yii \db \Expression ("( $ compiledFields) " )];
160+ foreach ($ notDeletedPK as $ value ){
161+ $ v = [];
162+ foreach ($ fields as $ key => $ f ){
163+ $ v [] = $ value [$ key ];
164+ }
165+ $ c = implode (', ' ,$ v );
166+ $ content [] = new \yii \db \Expression ("( $ c) " );
167+ }
168+ array_push ($ notIn ,$ content );
169+ array_push ($ compiledNotDeletedPK ,$ notIn );
170+ try {
171+ $ relModel ->deleteAll ($ compiledNotDeletedPK );
172+ } catch (\yii \db \IntegrityException $ exc ) {
173+ $ this ->addError ($ name , "Data can't be deleted because it's still used by another data. " );
174+ }
175+ } else {
176+ $ notDeletedFK = implode (' AND ' , $ notDeletedFK );
177+ $ compiledNotDeletedPK = implode (', ' , $ notDeletedPK );
178+ if (!empty ($ compiledNotDeletedPK )) {
179+ try {
180+ $ relModel ->deleteAll ($ notDeletedFK . ' AND ' . $ relPKAttr [0 ] . " NOT IN ( $ compiledNotDeletedPK) " );
181+
182+ } catch (\yii \db \IntegrityException $ exc ) {
183+ $ this ->addError ($ name , "Data can't be deleted because it's still used by another data. " );
184+ }
129185 }
130- print_r ("$ notDeletedFK AND " . implode (' AND ' , $ compiledNotDeletedPK )."\n" );
131- }
132- } else {
133- $ compiledNotDeletedPK = implode (', ' , $ notDeletedPK );
134- if (!empty ($ compiledNotDeletedPK )) {
135- $ relModel ->deleteAll ($ notDeletedFK . ' AND ' . $ relPKAttr [0 ] . " NOT IN ( $ compiledNotDeletedPK) " );
136186 }
137187 }
188+ } else {
189+ //Has One
138190 }
191+
139192 }
140193 }
141- }else {
194+ } else {
195+ //No Children left
142196 if (!$ this ->isNewRecord ) {
143197 $ relData = $ this ->getRelationData ();
144- foreach ($ relData as $ rel ){
198+ foreach ($ relData as $ rel ) {
145199 /* @var $relModel ActiveRecord */
146200 $ relModel = new $ rel ['modelClass ' ];
147201 $ condition = [];
148- foreach ($ rel ['link ' ] as $ k => $ v ){
149- $ condition [] = $ k . " = " . $ this ->$ v ;
202+ foreach ($ rel ['link ' ] as $ k => $ v ) {
203+ if (property_exists ($ this , $ v ))
204+ $ condition [] = $ k . " = " . $ this ->$ v ;
205+ }
206+ try {
207+ $ relModel ->deleteAll (implode (" AND " , $ condition ));
208+ } catch (\yii \db \IntegrityException $ exc ) {
209+ $ this ->addError ($ rel ['name ' ], "Data can't be deleted because it's still used by another data. " );
210+ $ error = 1 ;
150211 }
151- $ relModel ->deleteAll (implode (" AND " ,$ condition ));
152212 }
153213 }
154214 }
@@ -168,21 +228,22 @@ public function saveAll() {
168228 }
169229 }
170230
171- public function deleteWithRelated () {
231+ public function deleteWithRelated ()
232+ {
172233 /* @var $this ActiveRecord */
173234 $ db = $ this ->getDb ();
174235 $ trans = $ db ->beginTransaction ();
175236 try {
176237 $ error = 0 ;
177238 $ relData = $ this ->getRelationData ();
178239 foreach ($ relData as $ data ) {
179- if ($ data ['ismultiple ' ]){
240+ if ($ data ['ismultiple ' ]) {
180241 $ link = $ data ['link ' ];
181- if (count ($ this ->{$ data ['name ' ]})){
242+ if (count ($ this ->{$ data ['name ' ]})) {
182243 $ relPKAttr = $ this ->{$ data ['name ' ]}[0 ]->primaryKey ();
183244 $ isCompositePK = (count ($ relPKAttr ) > 1 );
184245 foreach ($ link as $ key => $ value ) {
185- if (isset ($ this ->$ value )){
246+ if (isset ($ this ->$ value )) {
186247 $ array [$ key ] = $ key . ' = ' . $ this ->$ value ;
187248 }
188249 }
@@ -194,7 +255,7 @@ public function deleteWithRelated() {
194255 $ trans ->rollback ();
195256 return false ;
196257 }
197- if ($ this ->delete ()){
258+ if ($ this ->delete ()) {
198259 $ trans ->commit ();
199260 return true ;
200261 }
@@ -206,8 +267,8 @@ public function deleteWithRelated() {
206267 }
207268
208269
209-
210- public function getRelationData () {
270+ public function getRelationData ()
271+ {
211272 $ ARMethods = get_class_methods ('\yii\db\ActiveRecord ' );
212273 $ modelMethods = get_class_methods ('\yii\base\Model ' );
213274 $ reflection = new \ReflectionClass ($ this );
@@ -218,32 +279,50 @@ public function getRelationData() {
218279 if (in_array ($ method ->name , $ ARMethods ) || in_array ($ method ->name , $ modelMethods )) {
219280 continue ;
220281 }
221- if ($ method ->name === 'bindModels ' ) {continue ;}
222- if ($ method ->name === 'attachBehaviorInternal ' ) {continue ;}
223- if ($ method ->name === 'loadAll ' ) {continue ;}
224- if ($ method ->name === 'saveAll ' ) {continue ;}
225- if ($ method ->name === 'getRelationData ' ) {continue ;}
226- if ($ method ->name === 'getAttributesWithRelatedAsPost ' ) {continue ;}
227- if ($ method ->name === 'getAttributesWithRelated ' ) {continue ;}
228- if ($ method ->name === 'deleteWithRelated ' ) {continue ;}
282+ if ($ method ->name === 'bindModels ' ) {
283+ continue ;
284+ }
285+ if ($ method ->name === 'attachBehaviorInternal ' ) {
286+ continue ;
287+ }
288+ if ($ method ->name === 'loadAll ' ) {
289+ continue ;
290+ }
291+ if ($ method ->name === 'saveAll ' ) {
292+ continue ;
293+ }
294+ if ($ method ->name === 'getRelationData ' ) {
295+ continue ;
296+ }
297+ if ($ method ->name === 'getAttributesWithRelatedAsPost ' ) {
298+ continue ;
299+ }
300+ if ($ method ->name === 'getAttributesWithRelated ' ) {
301+ continue ;
302+ }
303+ if ($ method ->name === 'deleteWithRelated ' ) {
304+ continue ;
305+ }
229306 try {
230- $ rel = call_user_func (array ($ this ,$ method ->name ));
231- if ($ rel instanceof \yii \db \ActiveQuery){
307+ $ rel = call_user_func (array ($ this , $ method ->name ));
308+ if ($ rel instanceof \yii \db \ActiveQuery) {
232309 $ stack [$ i ]['name ' ] = lcfirst (str_replace ('get ' , '' , $ method ->name ));
233310 $ stack [$ i ]['method ' ] = $ method ->name ;
234311 $ stack [$ i ]['ismultiple ' ] = $ rel ->multiple ;
235312 $ stack [$ i ]['modelClass ' ] = $ rel ->modelClass ;
236313 $ stack [$ i ]['link ' ] = $ rel ->link ;
237314 $ i ++;
238315 }
239- } catch (\yii \base \ErrorException $ exc ) {}
316+ } catch (\yii \base \ErrorException $ exc ) {
317+ }
240318 }
241319 return $ stack ;
242320 }
243321
244322 /* this function is deprecated */
245323
246- public function getAttributesWithRelatedAsPost () {
324+ public function getAttributesWithRelatedAsPost ()
325+ {
247326 $ return = [];
248327 $ shortName = StringHelper::basename (get_class ($ this ));
249328 $ return [$ shortName ] = $ this ->attributes ;
@@ -256,7 +335,8 @@ public function getAttributesWithRelatedAsPost() {
256335 return $ return ;
257336 }
258337
259- public function getAttributesWithRelated () {
338+ public function getAttributesWithRelated ()
339+ {
260340 $ return = $ this ->attributes ;
261341 foreach ($ this ->relatedRecords as $ name => $ records ) {
262342 foreach ($ records as $ index => $ record ) {
0 commit comments