Search code examples
phpforeach

PHP function with unknown number (Regexp type) $childIds[] = X,$child->id


Here is the structure of my categories in the database

Parent category A (category_id = 1)
Child category B (category_id = 2)
Child category C (category_id = 3)
Child category D (category_id = 4)
Child category E (category_id = 5)

Basically my Joomla extension does not allow you to classify a Page in several categories at the same time. But I managed to get around this by modifying some php files, and adding several category_id values (separated by commas)

My code that works. But it's just too long. I would like to simplify it. I had to create all the scenarios, depending on the position of the numbers.

My code :

// Get all child ids from this category
$categoryModel = ES::model('ClusterCategory');
$childs = $categoryModel->getChildCategories($activeCategory->id, [], SOCIAL_TYPE_PAGE, array('state' => SOCIAL_STATE_PUBLISHED));

$childIds = [];

foreach ($childs as $child) {
    $childIds[] = "1,$child->id";
    $childIds[] = "2,$child->id";
    $childIds[] = "3,$child->id";
    $childIds[] = "4,$child->id";
    $childIds[] = "5,$child->id";
    $childIds[] = "$child->id,1";
    $childIds[] = "$child->id,2";
    $childIds[] = "$child->id,3";
    $childIds[] = "$child->id,4";
    $childIds[] = "$child->id,5";   
    $childIds[] = "1,$child->id,2";
    $childIds[] = "2,$child->id,3";
    $childIds[] = "3,$child->id,4";
    $childIds[] = "4,$child->id,5";
    $childIds[] = "5,$child->id,1";
    $childIds[] = "2,$child->id,1";
    $childIds[] = "3,$child->id,2";
    $childIds[] = "4,$child->id,3";
    $childIds[] = "5,$child->id,4";
    $childIds[] = "1,$child->id,5";
    $childIds[] = $child->id;
}

My question : How to insert a variable instead of the number? I tried Regexp, and many other things.

As in an equation with an unknown. $childIds[] = X,$child->id,X;


Solution

  • You could use nested loops do do this.

    $categoryModel = ES::model('ClusterCategory');
    $childs = $categoryModel->getChildCategories($activeCategory->id, [], SOCIAL_TYPE_PAGE, array('state' => SOCIAL_STATE_PUBLISHED));
    $childIds = [];
    
    foreach ($childs as $child) {
        for ($i = 1; $i <= 5; $i++) {
            $childIds[] = "$i,$child->id";
            $childIds[] = "$child->id,$i";
            
            for ($j = 1; $j <= 5; $j++) {
                if ($i != $j) {
                    $childIds[] = "$i,$child->id,$j";
                    $childIds[] = "$i,$j,$child->id";
                    
                    for ($k = 1; $k <= 5; $k++) {
                        if ($i != $k && $j != $k) {
                            $childIds[] = "$i,$child->id,$j,$k";
                            $childIds[] = "$i,$j,$child->id,$k";
                            // Add more combinations as needed
                        }
                    }
                }
            }
        }
    }
    

    This way, you can easily adjust the range of numbers by changing the loop boundaries, and the code will be more maintainable.

    But since nested loops in general are a very bad idea you should consider using a recursive function instead.

    function generateCombinations($depth, $maxDepth, $currentCombination, $excludeValues, $childId, &$childIds) {
        if ($depth == $maxDepth) {
            $childIds[] = implode(',', $currentCombination);
            return;
        }
    
        for ($i = 1; $i <= 5; $i++) {
            if (!in_array($i, $excludeValues)) {
                $currentCombination[] = $i;
                generateCombinations($depth + 1, $maxDepth, $currentCombination, $excludeValues, $childId, $childIds);
                array_pop($currentCombination);
            }
        }
    }
    
    $categoryModel = ES::model('ClusterCategory');
    $childs = $categoryModel->getChildCategories($activeCategory->id, [], SOCIAL_TYPE_PAGE, array('state' => SOCIAL_STATE_PUBLISHED));
    
    $childIds = [];
    
    foreach ($childs as $child) {
        generateCombinations(0, 2, [$child->id], [], $child->id, $childIds);
        generateCombinations(0, 3, [$child->id], [], $child->id, $childIds);
        // Add more calls for additional combinations if needed
    }
    

    But to be completely honest the right way to solve this is to review your database structure.