фильтр массива для значений массива - PullRequest
1 голос
/ 20 марта 2020

У меня есть этот код, который выполняет работу по поиску имени опции, как я могу использовать его для поиска значения опции из массива.

$productspp ='[{
    "id": 4674388066436,
    "title": "1st march",
    "options": [{
        "id": 6046836162692,
        "product_id": 4674388066436,
        "name": "Size",
        "position": 1,
        "values": ["12", "24", "36"]
    }, {
        "id": 6067871875204,
        "product_id": 4674388066436,
        "name": "z",
        "position": 2,
        "values": ["blue", "green"]
    }, {
        "id": 6067871907972,
        "product_id": 4674388066436,
        "name": "Material",
        "position": 3,
        "values": ["silk", "cotton"]
    }],
}, {
    "id": 4674394325124,
    "title": "2nd march",
    "options": [{
        "id": 6046844190852,
        "product_id": 4674394325124,
        "name": "Title",
        "position": 1,
        "values": ["Default Title"]
    }],
}, {
    "id": 4679851704452,
    "title": "3rd marchhh",
    "options": [{
        "id": 6053112545412,
        "product_id": 4679851704452,
        "name": "Title",
        "position": 1,
        "values": ["Default Title"]
    }]
}]';

$array = json_decode($productspp,1);

    $filter_name555 ='options';
    $dummytstt ='values';
    $filter_value=  blue;


 $expected = array_filter($array, function($el) use ($filter_name555, $dummytstt, $filter_value) {

    return ( stripos($el[$filter_name555][0][$dummytstt], $filter_value) !== false ); 
}

}); 

, если пользователь выполнил поиск по параметру option_value, и он соответствует, то в нем должно быть указано, что product, поэтому в этом случае, если пользователь ищет шелк, он должен указать этот продукт, но не

для имени параметра, он работает для значения параметра, он не работает, так как stripos ожидает, что это будет строка, но здесь в данных это массив.

мы попытались in_array также отфильтровать, но это также не сработало

, когда мы ищем что-то вроде 12, 24, 36, синего или зеленого, тогда в этой части json должен быть указан список. я имею в виду этот продукт и код, который я дал выше, делает то же самое, но для имени опции. Вы можете видеть, что значение параметра является массивом. он может иметь более одного значения, поэтому мой код не работает.

{
    "id": 4674388066436,
    "title": "1st march",
    "options": [{
        "id": 6046836162692,
        "product_id": 4674388066436,
        "name": "Size",
        "position": 1,
        "values": ["12", "24", "36"]
    }, {
        "id": 6067871875204,
        "product_id": 4674388066436,
        "name": "z",
        "position": 2,
        "values": ["blue", "green"]
    }, {
        "id": 6067871907972,
        "product_id": 4674388066436,
        "name": "Material",
        "position": 3,
        "values": ["silk", "cotton"]
    }],
}

Ответы [ 2 ]

0 голосов
/ 21 марта 2020

Вам необходимо различать guish между значением массива или обычным значением, потому что они должны совпадать по-разному.

Одна вещь, которую вы можете сделать, это написать logi c для значения if является массивом, а затем форсирует любое другое значение в массив только из одного элемента.

$key = 'options';
$attr = 'values';
$search = 'blue';

$expected = array_filter($array, function($el) use ($key, $attr, $search) {
  $values = $el[$key];
  if (is_array($value)) {
    $values = array_column($value, $attr);
  } else {
    $value = array($value);
  }

  foreach ($value as $body) {
    foreach ((array)$body as $contents) {
      if (stripos($contents, $search) !== false) {
        return true;
      }
    }
  }
  return false;
}
0 голосов
/ 20 марта 2020

Ваша основная проблема c в том, что у вас есть многомерный массив, и вы не выполняете итерации на всех уровнях. Чтобы сделать эту работу, мне пришлось переработать всю логику c, но я надеялся, что это будет хорошим обучающим упражнением.

Функция array_filter работает только с заданным уровнем. Вы можете оставить его, но я предложу решение, которое просто использует вложенные циклы:

/**
 * Selects products where options match the searched one by removing the ones that don't match.
 */
function selectProductsWithMatchingOptions(array $products, string $filterName, string $filterValue): array
{
    foreach ($products as $key => $product) {
        if (!hasMatchingOption($product['options'], $filterName, $filterValue)) {
            unset($products[$key]);
        }
    }
    return $products;
}

/**
 * Checks whether the searched filter is within any of the options for the product.
 */
function hasMatchingOption(array $options, string $filterName, string $filterValue): bool
{
    foreach ($options as $option) {
        // this part takes care of "values", which is an array
        if (is_array($option[$filterName]) && valueIsListed($option[$filterName], $filterValue)) {
            return true;
        // this part takes care of "name", which is a string
        } elseif (is_string($option[$filterName]) && stringMatches($filterValue, $option[$filterName])) {
            return true;
        }
    }
    return false;
}

/**
 * Checks if a value is in the list of values.
 */
function valueIsListed(array $values, string $filterValue): bool
{
    // we have to iterate and check with stripos because in_array can't handle case
    foreach ($values as $value) {
        if (stringMatches($filterValue, $value)) {
            return true;
        }
    }
    return false;
}

function stringMatches(string $needle, string $haystack): bool
{
    return stripos($needle, $haystack) !== false;
}

Теперь, если вы протестируете это с вашим массивом:

$filtered = selectProductsWithMatchingOptions($array, 'name', 'mAterial');

или

$filtered = selectProductsWithMatchingOptions($array, 'values', 'BLUE');

дамп $filtered должен показать желаемые результаты.

Я сделал несколько функций, потому что я предпочитаю извлекать меньшие кусочки логики c. Это делает для более чистого кода. Альтернативой было бы сохранение логических значений в переменных, чтобы узнать, нашли ли мы совпадение или нет, и это приводит к снижению читабельности. Кроме того, таким образом мы можем более элегантно отказаться от l oop, возвращая true, как только мы найдем совпадение. Это лучше, чем break, возможно, через несколько уровней.

Обратите внимание, что я не передал ключ 'options' в качестве параметра, потому что он единственный, который может быть повторен - эта функция выиграла ' t работает на 'id' или 'title'. Его тоже можно изменить, но я оставлю это на ваше усмотрение.

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

...