Рекурсивный поиск по массиву - следите за порядком и перебирайте массив - PullRequest
0 голосов
/ 29 сентября 2018

При доступе к сценарию, который я пишу, вы передаете путь категории к нему при доступе к странице.Затем сценарий сравнивает данные с массивом фактических категорий или ветвью, которая должна быть связана с этой категорией.

Я устанавливаю родителей и всех его детей в tree, а затем снижаюфилиал и сравнение данных, чтобы убедиться, что клиент использует правильный URL.Вот краткий пример того, как работает код:

// Customer is accessing from site.com/store/some-cat/some-othercat
// We pass those variables with the htaccess to script.php?var=$1,$2
// We then explode that to make an array on $var[0] and $var[1]
$categoryMap = explode(",", $_GET['var']);
$categoryID = array();
$categoryInfoMap = array();
foreach ($categoryMap as $a) {
    $categoryIDs[] = trim($a);
}
$getCategoryInfo = $db->fn->query("SELECT * FROM store_category");
....
// Inside while loop...
     $categoryInfoMap[] = $db->result[]; // stored whole results as array
// End of the while loop
$masterKey = $mainClass->findKeyInDbArray($categoryInfoMap, 'c.path', $categoryMap[0]);
if ((isset($masterKey) && $masterKey === "0") || !empty($masterKey)) {
    $thisId = $categoryInfoMap[$masterKey]['c.id'];
    $thisPath = $categoryInfoMap[$masterKey]['c.path'];
    $thisName = $categoryInfoMap[$masterKey]['c.name'];
    $tree = $mainClass->buildTree($categoryInfoMap);
    $children = $tree['children'][$thisId];
    $childrenItems = "";
    foreach ($categoryIDs as $cid) {
        // One of the categories entered doesnt exist at all so we redirect,
        // else we will go through them and make sure theyre apart of the branch
        if (!$mainClass->recursive_array_search($cid, $tree)) {
            ... redirect them somewhere and die()
        } else {
            if (!$mainClass->recursive_array_search($cid, $children)) {
                ... redirect them somewhere and die()
            } else {
                !!!!!!!!!!!!============!!!!!!!!!!!!!!
                    THIS IS THE IMPORTANT PART HERE
                !!!!!!!!!!!!============!!!!!!!!!!!!!!
            }
        }
    }
}
... Rest of the script which works for now

Вот функции, использованные в приведенном выше коде

public function findKeyInDbArray($products, $field, $value) {
    foreach($products as $key => $product) {
        if ($product[$field] === $value) {
            return "$key";
        }
    }
    return NULL;
}
public function buildTree($arr) {
    $tree = array(
        'children' => array()
    );
    $index = array(0=>&$tree);
    foreach ($arr as $key => $val) {
        $parent = &$index[$val['c.parentcatid']];
        $node = $val;
        $parent['children'][$val['c.id']] = $node;
        $index[$val['c.id']] = &$parent['children'][$val['c.id']];
    }
    return $tree;
}
public function recursive_array_search($needle,$haystack) {
    foreach($haystack as $key=>$value) {
        $current_key=$key;
        if($needle===$value OR (is_array($value) && $this->recursive_array_search($needle,$value) !== false)) {
            return $current_key;
        }
    }
    return false;
}

А вот пример массива дерева из родительского узлавниз.Коротко из соображений видимости

Array(
[c.id] => 1
[c.name] => Radios
[c.path] => radios
[c.parentcatid] => 0
[children] => (
    [2] => (
        [0] => 2
        ....
        [children] => (
            [3] => (
                [c.id] => 3
                ....
                [c.parentcatid] => 2
            ),
            [4] => (
                [c.id] => 4
                ....
                [c.parentcatid] => 2
            )
        )
    )
    ......
    [10] => (
        [0] => 10
        ....
        [c.parentcatid] => 1
    )
)

SO на хорошие биты

В данный момент код работает, чтобы доказать, что ветви имеют совпадающие переменные из своего дерева.Если путь к элементу, который является переменной, которую мы используем для сравнения с URL $var, совпадает, то он будет продолжаться и работать.так что если в ветке существуют следующие значения:

array(c.path => 'foo'),
array(c.path => 'bar')

И я посещаю скрипт как site.com/store/foo/bar, тогда все прекрасно работает.Если я захожу на сайт как site.com/store/foo/notBar, то это не удастся, так как переменная notBar не является членом этой ветки.Это идеально верно?Все должно работать!За исключением того, что это не так и по уважительной причине.


Проблема здесь

Если элемент соответствует в ветви, то он прошел проверку, и этоконец проверки.Не, если элемент передается в неправильном порядке, таком как site.com/store/bar/foo, тогда он все еще технически имеет хорошие переменные в нем, но он НЕ ДОЛЖЕН проходить, так как структура не в том порядке, в котором она идет по родительскому массиву.Аналогично, если другая ветвь дальше по дереву, скажем, существует barwithNoChildren, я могу поменять ее с foo или bar и все равно пройти, даже если ничего не должно быть .

Надеюсь, вы понимаете, о чем я спрашиваю, и можете помочь предложить способы обойти это.Последние несколько дней я ломал голову над этой системой, и, поскольку им нужны причудливые URL-адреса по seo и по другим причинам, это оказалось намного сложнее, чем я планировал.Спасибо за любые предложения!

1 Ответ

0 голосов
/ 29 сентября 2018

Древовидная структура не очень полезна для этой цели.Вы должны подумать о том, как создать структуру данных, которая облегчит вам сопоставление ввода.Поскольку вход вашей категории описывает ветвь дерева, лучше всего создать массив, который вы можете использовать для эффективного сопоставления описаний веток с вашими категориями.

Давайте создадим массив, в котором ключами являются путидля каждой категории, как описано их слагами, а значения являются идентификаторами категорий.Затем мы можем сразу определить соответствующую категорию или потерпеть неудачу, если путь не находится в массиве.

Эта структура, похожая на крошку, является еще одним шаблоном, который обычно используется с категориями.Помимо дерева и плоской идентификационной карты, вы можете делать практически все, что вам нужно.Главное, что нужно сделать, это подумать о создании различных структур с вашими данными для решения разных задач.Как правило, более эффективно и менее подвержено ошибкам создавать новую структуру, с которой легко работать, чем создавать сложную логику, чтобы попытаться работать с существующей структурой, которая не поддается выполнению поставленной задачи.

<?php
//Mock category records, would come from the DB in the real world
$categoryRecords = [
    ['id' => 1, 'title' => 'Radios', 'slug' => 'radios', 'parent_id' => 0],
    ['id' => 2, 'title' => 'Accessories', 'slug' => 'misc', 'parent_id' => 1],
    ['id' => 3, 'title' => 'Motorola', 'slug' => 'motorola', 'parent_id' => 1],
    ['id' => 4, 'title' => 'Handheld', 'slug' => 'handheld', 'parent_id' => 3],
    ['id' => 5, 'title' => 'Mobile', 'slug' => 'mobile', 'parent_id' => 3]
];

//Create an array that maps parent IDs to primary keys
$idMap = [];
foreach ($categoryRecords as $currRecord)
{
    $idMap[$currRecord['id']] = $currRecord;
}

//Traverse the flat array and build the path lines
$paths = [];
$categoryIds = array_keys($idMap);
foreach ($categoryIds as $currLeafId)
{
    $currCategoryId = $currLeafId;

    $currLine = [];

    do
    {
        $currLine[]     = $idMap[$currCategoryId]['slug'];
        $currCategoryId = $idMap[$currCategoryId]['parent_id'];
    } while ($currCategoryId != 0);

    $currLine = array_reverse($currLine);
    $currPath = implode('/', $currLine);
    $paths[$currPath] = $currLeafId;
}

//Join your input - $_GET['var'] in your example
$inputPath = implode('/', ['radios', 'motorola', 'handheld']);

//Now you can see if the incoming path matched a category
if(array_key_exists($inputPath, $paths))
{
    $category = $categoryRecords[$paths[$inputPath]];

    echo 'Matched category: '.$category['title'].PHP_EOL;
}
else
{
    echo 'Invalid category path';
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...