Вывод данных из БД php PDO

537
09 мая 2017, 04:16

Ребят, всем привет. Есть такая БД:

  • Таблица products: id, title, link (для того, чтобы можно по ссылке открывать тот или иной товар, не только по ID);
  • Таблица prod_prop: id, product_id, property_id, value;
    • Связь М:М, обеспечивает множественные свойства для товаров
  • Таблица properties: id, title

Следующая функция возвращает данные, которые берутся из этих таблиц:

public static function getProductByName($link) {
        $db = Db::getConnection();
        $sql = 'SELECT p.*, 
                cat.name AS category_name, 
                cat.link AS category_link, 
                prop.title AS property_title,
                pr_prop.value AS property_value
                FROM products AS p
                JOIN category AS cat ON cat.id = p.category_id
                JOIN product_prop AS pr_prop ON pr_prop.product_id = p.id
                JOIN properties AS prop ON prop.id = pr_prop.property_id
                WHERE p.link = :link';        
        $result = $db->prepare($sql);
        $result->bindParam(':link', $link, PDO::PARAM_INT);        
        $result->setFetchMode(PDO::FETCH_ASSOC);
        $result->execute();        
        return $result->fetch();
    }

Проблема - данная функция возвращает лишь первые строки из таблиц prod_prop и properties, т.е. если в таблице prod_prop указано 3 свойства для 1 товара, он возвращает лишь одно.

Вопрос: как сделать, чтобы свойства из данных таблиц возвращались в виде ассоциативного массива (т.е. чтобы попарно шло, пример массива, который хотелось бы видеть, будет ниже)? Нужно для вывода на страничке товара через цикл foreach.

Заранее спасибо!

Пример массива:

array(
    array(
        'title' => 'Длина',
        'value' => '40',
    ),
    array(
        'title' => 'Страна',
        'value' => 'Эквадор',
    ),
    array(
        'title' => 'Цена',
        'value' => '100',
    )
);

UPD сделал следующее:

$product = Product::getProductByName($link);
var_dump($product);

Ничего дельного не вышло, в БД 3 записи по этому ID, выводится лишь одна, вот дамп:

array(16) {
  ["id"]=>
  string(1) "6"
  ["link"]=>
  string(10) "sweetbox-5"
  ["title"]=>
  string(44) "Коробка со сладостями #5 "
  ["description"]=>
  string(1) "0"
  ["meta_keywords"]=>
  string(1) "0"
  ["meta_description"]=>
  string(1) "0"
  ["price"]=>
  string(4) "5799"
  ["is_discount"]=>
  string(1) "1"
  ["discount_price"]=>
  NULL
  ["category_id"]=>
  string(1) "3"
  ["is_recommended"]=>
  string(1) "1"
  ["params"]=>
  NULL
  ["category_name"]=>
  string(40) "Коробки со сладостями"
  ["category_link"]=>
  string(8) "sweetbox"
  ["property_title"]=>
  string(29) "Количество букв"
  ["property_value"]=>
  string(1) "5"
}

UPD2: Поменял на fetchAll. Получается следующее:

array(3) {
  [0]=>
  array(15) {
    ["id"]=>
    string(1) "6"
    ["link"]=>
    string(10) "sweetbox-5"
    ["title"]=>
    string(44) "Коробка со сладостями #5 "
    ["description"]=>
    string(1) "0"
    ["meta_keywords"]=>
    string(1) "0"
    ["meta_description"]=>
    string(1) "0"
    ["price"]=>
    string(4) "5799"
    ["is_discount"]=>
    string(1) "1"
    ["discount_price"]=>
    NULL
    ["category_id"]=>
    string(1) "3"
    ["is_recommended"]=>
    string(1) "1"
    ["category_name"]=>
    string(40) "Коробки со сладостями"
    ["category_link"]=>
    string(8) "sweetbox"
    ["property_title"]=>
    string(29) "Количество букв"
    ["property_value"]=>
    string(1) "5"
  }
  [1]=>
  array(15) {
    ["id"]=>
    string(1) "6"
    ["link"]=>
    string(10) "sweetbox-5"
    ["title"]=>
    string(44) "Коробка со сладостями #5 "
    ["description"]=>
    string(1) "0"
    ["meta_keywords"]=>
    string(1) "0"
    ["meta_description"]=>
    string(1) "0"
    ["price"]=>
    string(4) "5799"
    ["is_discount"]=>
    string(1) "1"
    ["discount_price"]=>
    NULL
    ["category_id"]=>
    string(1) "3"
    ["is_recommended"]=>
    string(1) "1"
    ["category_name"]=>
    string(40) "Коробки со сладостями"
    ["category_link"]=>
    string(8) "sweetbox"
    ["property_title"]=>
    string(33) "Количество цветов"
    ["property_value"]=>
    string(2) "23"
  }
  [2]=>
  array(15) {
    ["id"]=>
    string(1) "6"
    ["link"]=>
    string(10) "sweetbox-5"
    ["title"]=>
    string(44) "Коробка со сладостями #5 "
    ["description"]=>
    string(1) "0"
    ["meta_keywords"]=>
    string(1) "0"
    ["meta_description"]=>
    string(1) "0"
    ["price"]=>
    string(4) "5799"
    ["is_discount"]=>
    string(1) "1"
    ["discount_price"]=>
    NULL
    ["category_id"]=>
    string(1) "3"
    ["is_recommended"]=>
    string(1) "1"
    ["category_name"]=>
    string(40) "Коробки со сладостями"
    ["category_link"]=>
    string(8) "sweetbox"
    ["property_title"]=>
    string(10) "Длина"
    ["property_value"]=>
    string(3) "100"
  }
} 

UPD3: Цикл while:

$i = 0;
        while ($row = $result->fetchAll()) {
            $productList['product']['id']                       = $row[$i]['id'];
            $productList['product']['link']                     = $row[$i]['link'];
            $productList['product']['title']                    = $row[$i]['title'];
            $productList['product']['description']              = $row[$i]['description'];
            $productList['product']['meta_keywords']            = $row[$i]['meta_keywords'];
            $productList['product']['meta_description']         = $row[$i]['meta_description'];
            $productList['product']['price']                    = $row[$i]['price'];
            $productList['product']['is_discount']              = $row[$i]['is_discount'];
            $productList['product']['discount_price']           = $row[$i]['discount_price'];
            $productList['product']['category_id']              = $row[$i]['category_id'];
            $productList['product']['is_recommended']           = $row[$i]['is_recommended'];
            $productList['properties'][] = ['title' => $row[$i]['property_title'], 'value' => $row[$i]['property_value']];
            $i++;
        } 

Результат цикла:

array(2) {
  ["product"]=>
  array(11) {
    ["id"]=>
    string(1) "6"
    ["link"]=>
    string(10) "sweetbox-5"
    ["title"]=>
    string(44) "Коробка со сладостями #5 "
    ["description"]=>
    string(1) "0"
    ["meta_keywords"]=>
    string(1) "0"
    ["meta_description"]=>
    string(1) "0"
    ["price"]=>
    string(4) "5799"
    ["is_discount"]=>
    string(1) "1"
    ["discount_price"]=>
    NULL
    ["category_id"]=>
    string(1) "3"
    ["is_recommended"]=>
    string(1) "1"
  }
  ["properties"]=>
  array(1) {
    [0]=>
    array(2) {
      ["title"]=>
      string(29) "Количество букв"
      ["value"]=>
      string(1) "5"
    }
  }
}
Answer 1

вот получили вы $product с помощью fetchAll. В результате имеете 3 строки, в каждой строки первые несколько значений одинаковы, два последних - ваши свойства - разные. Упрощенно представим это так:

$product = [
    [ 'id' => 1, 'title' => 'товар', 'property_title' => 'длина',  'property_value' => 100], 
    [ 'id' => 1, 'title' => 'товар', 'property_title' => 'высота', 'property_value' => 200], 
    [ 'id' => 1, 'title' => 'товар', 'property_title' => 'ширина', 'property_value' => 300], 
];

А вы хотите получить массив вида

$product = [
    'id' => 1,
    'title' => 'товар',
    'properties' => [
         ['title' => 'Длина',  'value' => 100],
         ['title' => 'высота', 'value' => 200],
         ['title' => 'ширина', 'value' => 300],
    ],
];

Для этого все повторяющиеся данные возьмите из первой строки. Дальше циклом выберите значения свойств.

$item = $product[0];
foreach($product as $p){
    $item['properties'][] = [
           'title' => $p['property_title', 
           'value' => $p['property_value']
        ];
} 

при желании удалите исходные property_title и value из $item:

unset($item['property_title']);
unset($item['property_value']);

в результате получите приведенный выше массив $item со вложенными массивом свойств.
Вместо такого цикла можно и другие варианты привести, например, array_map. А также задачу можно решить с помощью двух запросов вместо одного. Первый извлечет нужную информацию о товаре (1 строка), а второй 3 строки его свойств. С одной стороны лишний запрос, с другой нет дополнительного джойна и передачи большего объема данных, который впрочем тут не критичен.

Answer 2

Добрый день!

Иcпользуйте fetch, результаты запроса обрабатывайте циклом while (не foreach). Т.е. вместо:

return $result->fetch();

Используйте:

while ($row = $result->fetch(PDO::FETCH_LAZY))
{
   echo $row->name; //Ну или что вы там с этим хотели делать?
}
READ ALSO
Исключить из выборки

Исключить из выборки

У меня запрос который возвращает вот такой результат

296
PHP, MYSQL - Ошибка expects at least … parameters (Помогите пожалуйста)

PHP, MYSQL - Ошибка expects at least … parameters (Помогите пожалуйста)

Только начал изучать phpСоздаю чат

237
RedBean условие “И” внутри запроса

RedBean условие “И” внутри запроса

Всем привет, не так давно начал использовать ORM RedBeanPhpИ по итогам двух дней, копания в доках не могу понять как прописать двойное условие для...

246
Как сохранить объект в базу используя Spring Boot и Hibernate 5?

Как сохранить объект в базу используя Spring Boot и Hibernate 5?

Сейчас практикуюсь со Spring Boot + Hibernate 5 + mysqlНе получается сохранить объект в бд

293