@@ -1430,22 +1430,13 @@ public function newModelInstance($attributes = [])
1430
1430
*/
1431
1431
protected function parseWithRelations (array $ relations )
1432
1432
{
1433
- $ results = [];
1433
+ if ($ relations === []) {
1434
+ return [];
1435
+ }
1434
1436
1435
- foreach ($ relations as $ name => $ constraints ) {
1436
- // If the "name" value is a numeric key, we can assume that no constraints
1437
- // have been specified. We will just put an empty Closure there so that
1438
- // we can treat these all the same while we are looping through them.
1439
- if (is_numeric ($ name )) {
1440
- $ name = $ constraints ;
1441
-
1442
- [$ name , $ constraints ] = str_contains ($ name , ': ' )
1443
- ? $ this ->createSelectWithConstraint ($ name )
1444
- : [$ name , static function () {
1445
- //
1446
- }];
1447
- }
1437
+ $ results = [];
1448
1438
1439
+ foreach ($ this ->prepareNestedWithRelationships ($ relations ) as $ name => $ constraints ) {
1449
1440
// We need to separate out any nested includes, which allows the developers
1450
1441
// to load deep relationships using "dots" without stating each level of
1451
1442
// the relationship with its own key in the array of eager-load names.
@@ -1457,6 +1448,91 @@ protected function parseWithRelations(array $relations)
1457
1448
return $ results ;
1458
1449
}
1459
1450
1451
+ /**
1452
+ * Prepare nested with relationships.
1453
+ *
1454
+ * @param array $relations
1455
+ * @param string $prefix
1456
+ * @return array
1457
+ */
1458
+ protected function prepareNestedWithRelationships ($ relations , $ prefix = '' )
1459
+ {
1460
+ $ preparedRelationships = [];
1461
+
1462
+ if ($ prefix !== '' ) {
1463
+ $ prefix .= '. ' ;
1464
+ }
1465
+
1466
+ // If any of the relationships are formatted with the [$attribute => array()]
1467
+ // syntax, we shall loop over the nested relations and prepend each key of
1468
+ // this array while flattening into the traditional dot notation format.
1469
+ foreach ($ relations as $ key => $ value ) {
1470
+ if (! is_string ($ key ) || ! is_array ($ value )) {
1471
+ continue ;
1472
+ }
1473
+
1474
+ [$ attribute , $ attributeSelectConstraint ] = $ this ->parseNameAndAttributeSelectionConstraint ($ key );
1475
+
1476
+ $ preparedRelationships = array_merge (
1477
+ $ preparedRelationships ,
1478
+ ["{$ prefix }{$ attribute }" => $ attributeSelectConstraint ],
1479
+ $ this ->prepareNestedWithRelationships ($ value , "{$ prefix }{$ attribute }" ),
1480
+ );
1481
+
1482
+ unset($ relations [$ key ]);
1483
+ }
1484
+
1485
+ // We now know that the remaining relationships are in a dot notation format
1486
+ // and may be a string or Closure. We'll loop over them and ensure all of
1487
+ // the present Closures are merged + strings are made into constraints.
1488
+ foreach ($ relations as $ key => $ value ) {
1489
+ if (is_numeric ($ key ) && is_string ($ value )) {
1490
+ [$ key , $ value ] = $ this ->parseNameAndAttributeSelectionConstraint ($ value );
1491
+ }
1492
+
1493
+ $ preparedRelationships [$ prefix .$ key ] = $ this ->combineConstraints ([
1494
+ $ value ,
1495
+ $ preparedRelationships [$ prefix .$ key ] ?? static function () {
1496
+ //
1497
+ },
1498
+ ]);
1499
+ }
1500
+
1501
+ return $ preparedRelationships ;
1502
+ }
1503
+
1504
+ /**
1505
+ * Combine an array of constraints into a single constraint.
1506
+ *
1507
+ * @param array $constraints
1508
+ * @return \Closure
1509
+ */
1510
+ protected function combineConstraints (array $ constraints )
1511
+ {
1512
+ return function ($ builder ) use ($ constraints ) {
1513
+ foreach ($ constraints as $ constraint ) {
1514
+ $ builder = $ constraint ($ builder ) ?? $ builder ;
1515
+ }
1516
+
1517
+ return $ builder ;
1518
+ };
1519
+ }
1520
+
1521
+ /**
1522
+ * Parse the attribute select constraints from the name.
1523
+ *
1524
+ * @param string $name
1525
+ * @return array
1526
+ */
1527
+ protected function parseNameAndAttributeSelectionConstraint ($ name )
1528
+ {
1529
+ return str_contains ($ name , ': ' )
1530
+ ? $ this ->createSelectWithConstraint ($ name )
1531
+ : [$ name , static function () {
1532
+ //
1533
+ }];
1534
+ }
1535
+
1460
1536
/**
1461
1537
* Create a constraint to select the given columns for the relation.
1462
1538
*
0 commit comments