递归函数中的States / Cities数组,用于输出带有optgroup的select

时间:2014-11-26 07:41:51

标签: php

我有一系列的州/城市,其中每个元素都有一个$cities['parent']键(状态值为0> 0或城市,如下所示:

$cities = array(
    '1' => array(
        'id' => '1',
        'parent' => '0',
        'name' => 'California',
    ),
    '2' => array(
        'id' => '2',
        'parent' => '0',
        'name' => 'Texas',
    ),
    '3' => array(
        'id' => '3',
        'parent' => '0',
        'name' => 'Florida',
    ),
    '4' => array(
        'id' => '4',
        'parent' => '1',
        'name' => 'Los Angeles',
    ),
    '5' => array(
        'id' => '5',
        'parent' => '1',
        'name' => 'San Francisco',
    ),
    '6' => array(
        'id' => '6',
        'parent' => '1',
        'name' => 'Sacramento',
    ),
    '7' => array(
        'id' => '7',
        'parent' => '2',
        'name' => 'Houston',
    ),
    '8' => array(
        'id' => '8',
        'parent' => '2',
        'name' => 'Dallas',
    ),
    '9' => array(
        'id' => '9',
        'parent' => '3',
        'name' => 'Miami',
    ),
    '10' => array(
        'id' => '10',
        'parent' => '3',
        'name' => 'Orlando',
    ),
)

我还有一个递归函数来生成<select>选项,如下所示:

function citiesSelect($ancestor, $array, $level, $selected = 0) {
    $has_children = false;
    foreach($array as $key => $value) {
        if ($value['parent'] == $ancestor) {       
            if ($has_children === false && $ancestor) {
                $has_children = true;
            }
            ?>
            <option value="<?php echo $value['id'] ?>" <?php echo ($value['id']) == $selected ? ' selected' : ''; ?>><?php echo $value['name']; ?></option>
            <?php
            citiesSelect($key, $array, $level, $selected);
        }
    }
}

我记得这一点:

<select>
    <?php citiesSelect(0, $cities, 0); ?>
</select>

这很好(这是一个工作小提琴:http://phpfiddle.org/main/code/uiax-n03q)但是出现了一个问题:我想将状态置于<optroup>中,因此它们不可选择,并导致{ {1}}像这样:

<select>

没关系:如何实现这个目标?

提前致谢

编辑:感谢答案建议分成2个数组,但很抱歉我无法修改它!该阵列还成功地提供了另一个经典菜单(<select> <optgroup label="California"> <option value="4">Los Angeles</option> <option value="5">San Francisco</option> <option value="6">Sacramento</option> </optgroup> <optgroup label="Texas"> <option value="7">Houston</option> <option value="8">Dallas</option> </optgroup> <optgroup label="Florida"> <option value="9">Miami</option> <option value="10">Orlando</option> </optgroup> </select> ),无论如何我可以有第三个级别:

<ul>...</ul>

5 个答案:

答案 0 :(得分:1)

您正尝试使用尽可能少的语言结构(数组和函数)一次完成所有操作。这样你就会得到难以编写的复杂代码,以后会很难阅读和维护。

这样做的一种方法是:

$states = [
    'California' => [
         [
              'id' => 1,
              'name' => 'Los Angeles'
         ],
         [
              'id' => 1,
              'name' => 'San Francisco'
         ]
    ],
    'Florida' => [
         [
              'id' => 1,
              'name' => 'Orlando'
         ],
         ...
    ],
    ....
]

这样你可以像这样迭代:

echo "<select>";
foreach ($states as $state) {
    echo "<optgroup label='{$state}>";
    foreach ($state as $city) {
        echo "<option value='{$city['id']}'>{$city['name']}</option>" ;
    }
}
echo "</select>"

答案 1 :(得分:0)

我会把它分成两个不同的列表,一个用于州,另一个用于城市。或者,更好的是,创建一个两级数组:在第一级保持状态并将所有城市从一个状态移动到存储为该状态属性的新列表。像这样:

$states = array(
    '1' => array(
        'id' => '1',
        'name' => 'California',
        'cities' => array(
            '4' => array(
                'id' => '4',
                'name' => 'Los Angeles',
            ),
            '5' => array(
                'id' => '5',
                'name' => 'San Francisco',
            ),
            '6' => array(
                'id' => '6',
                'name' => 'Sacramento',
            ),
        ),
    ),
    '2' => array(
        'id' => '2',
        'name' => 'Texas',
        'cities' => array(
            '7' => array(
                'id' => '7',
                'name' => 'Houston',
            ),
            '8' => array(
                'id' => '8',
                'name' => 'Dallas',
            ),
        ),
    ),
    '3' => array(
        'id' => '3',
        'name' => 'Florida',
        'cities' => array(
            '9' => array(
                'id' => '9',
                'name' => 'Miami',
            ),
            '10' => array(
                'id' => '10',
                'name' => 'Orlando',
            ),
        ),
    ),
);

现在,代码变得更加清晰:

function citiesSelect(array $listStates, $selected = 0) {
    foreach($listStates as $stateId => $stateInfo) {
        ?>
        <optgroup label="<?php echo($stateInfo['name']); ?>">
        <?php
        foreach ($stateInfo['cities'] as $cityId => $cityInfo) {
            ?>
            <option value="<?php echo $cityInfo['id'] ?>" <?php echo ($cityInfo['id']) == $selected ? ' selected' : ''; ?>><?php echo $cityInfo['name']; ?></option>
            <?php
        }
        ?>
        </optgroup>
        <?php
    }
}

答案 2 :(得分:0)

我认为这会对你有所帮助,我会改变你的风格,但你可以解决它。

<?php
    function citiesSelect($ancestor, $array, $level, $selected = 0) {
        $has_children = false;

        foreach($array as $stateName => $city)
        {
            foreach($city as $key => $value) {
                ?>
                <option value="<?php echo $value['id'] ?>" <?php echo ($value['id']) == $selected ? ' selected' : ''; ?>><?php echo $value['name']; ?></option>
                <?php
            }
        }
    }

    $cities = array(
        '1' => array(
            'id' => '1',
            'parent' => '0',
            'name' => 'California',
        ),
        '2' => array(
            'id' => '2',
            'parent' => '0',
            'name' => 'Texas',
        ),
        '3' => array(
            'id' => '3',
            'parent' => '0',
            'name' => 'Florida',
        ),
        '4' => array(
            'id' => '4',
            'parent' => '1',
            'name' => 'Los Angeles',
        ),
        '5' => array(
            'id' => '5',
            'parent' => '1',
            'name' => 'San Francisco',
        ),
        '6' => array(
            'id' => '6',
            'parent' => '1',
            'name' => 'Sacramento',
        ),
        '7' => array(
            'id' => '7',
            'parent' => '2',
            'name' => 'Houston',
        ),
        '8' => array(
            'id' => '8',
            'parent' => '2',
            'name' => 'Dallas',
        ),
        '9' => array(
            'id' => '9',
            'parent' => '3',
            'name' => 'Miami',
        ),
        '10' => array(
            'id' => '10',
            'parent' => '3',
            'name' => 'Orlando',
        ),
    );

    $states = array();
    foreach($cities as $id=>$city)
    {
        if (isset($cities[$city['parent']]['name']))
            $states[$cities[$city['parent']]['name']][] = $city;
    }


    ?>
    <select>
        <?php citiesSelect(0, $states, 0); ?>
    </select>

答案 3 :(得分:0)

最后我用这个函数对它进行了整理(稍微改进了一下,处理嵌套的第三/第四/等级的缩进):

function citiesSelect($parent, $array, $level, $selected = 0) {
    $has_children = false;
    foreach($array as $key => $value) {
        if ($value['parent'] == $parent) {       
            if ($has_children === false && $parent) {
                $has_children = true;
                $level += 1;
            } else if ($parent == 0) {
                echo '<optgroup label="' . $value['name'] . '">' . "\n";    
            }
            if ($parent > 0) { ?>
            <option value="<?php echo $value['id'] ?>" <?php echo ($value['id']) == $selected ? 'selected' : ''; ?>>
                <?php echo str_repeat('&rsaquo; ',$level);?><?php echo $value['name']; ?>
            </option>
            <?php
            }
            citiesSelect($key, $array, $level);
            if ($parent == 0) { echo '</optgroup>'; };
        }
    }
}

这是working fiddle

感谢大家的耐心和花费的时间

答案 4 :(得分:0)

您需要为optgroup添加if else条件,只需像这样更改您的功能

<?php
function citiesSelect($ancestor, $array, $level, $selected = 0) {
    $has_children = false;
    $previousPid = '';

    foreach($array as $key => $value) {
        if ($value['parent'] == $ancestor) {                   
            if ($has_children === false && $ancestor) {
                $has_children = true;
            }

        if(!$has_children){
            if($previousPid && $previousPid!=$value['id']){
                echo '</optgroup>';
            }
            echo '<optgroup label="'.$value['name'].'">';           
        }else{                  
 ?>
 <option value="<?php echo $value['id'] ?>" <?php echo ($value['id']) == $selected ? ' selected' : ''; ?>><?php echo $value['name']; ?></option>
 <?php
        }       
            citiesSelect($key, $array, $level, $selected);
        }
        $previousPid = $key;            
    }       
}
?>