1

Тема: Масив

Привіт друзі.Маю логічний ступор на етапі розробки одного сервісу.
Є массив з ідентифікаторами ID.Беру for і перебираю масив. Під час перебору роблю запит в БД і витягую ще два ідентифікатори companyId та productId.Ці. два ідентифікатори хаотично повторюються. І тепер власне запитання:
Потрібно зробити асоціативний масив такого вигляду:
companyId1=>productId1=>agreementId1
companyId1=>productId1=>agreementId2
companyId1=>productId2=>agreementId3
і так далі. Другу годину хожу по колу і нічого не можу придумати

2

Re: Масив

if(isset($_POST['create'])){
            for($i=0;$i<count($_POST['agreementId']);$i++){
                $agreement = Agreements::getAgreementById($_POST['agreementId'][$i]);
                $product = Products::getProductById($agreement['product_id']);
                $company = Company::getCompanyById($product['company_id']);
                
                
            }
        }

це для розуміння

3 Востаннє редагувалося koala (04.11.2019 21:22:39)

Re: Масив

Просто масив масивів. Перед циклом:
$arr = array();
Всередині:

if(array_key_exists($companyId, $arr))
   $arr[$companyId][$productId] = $agreementId;
else
  $arr[$companyId] = array( $productId => $agreementId );

Вибачте, пишу з телефона і взагалі давно на PHP не писав.

Подякували: Intrerio1

4

Re: Масив

koala написав:

Просто масив масивів. Перед циклом:
$arr = array();
Всередині:

if(array_key_exists($companyId, $arr))
   $arr[$companyId][$productId] = $agreementId;
else
  $arr[$companyId] = array( $productId => $agreementId );

Вибачте, пишу з телефона і взагалі давно на PHP не писав.

Я подібний масив вже пробував зробити, навіть дещо коротше, але виникає наступна проблема, як потім його в циклі вийняти по поличкам companyId,productId та відповідно agreementId адже порядковим номером елементу в масиві буде ідентифікатор компанії чи продукту і key=>value вже не дуже допомагає або я просто туплю на вечір

5 Востаннє редагувалося koala (04.11.2019 21:47:15)

Re: Масив

foreach ($arr as $companyId => $prod_agr)
    foreach($prod_agr as $productId => $agreementId) {
       //зробити щось на "поличці" $companyId, $productId, $agreementId
}

Або детальніше розпишіть, що є в таблицях. Як співвідносяться компанії та продукти, n:n чи 1:n? Скільки може бути угод на один продукт? Що, зрештою, треба робити в кінці - може, треба скласти один складний запит до БД, а не кілька простих, а потім зліплювати?

Подякували: flatliner, leofun012

6

Re: Масив

koala написав:
foreach ($arr as $companyId => $prod_agr)
    foreach($prod_agr as $productId => $agreementId) {
       //зробити щось на "поличці" $companyId, $productId, $agreementId
}

Або детальніше розпишіть, що є в таблицях. Як співвідносяться компанії та продукти, n:n чи 1:n? Скільки може бути угод на один продукт? Що, зрештою, треба робити в кінці - може, треба скласти один складний запит до БД, а не кілька простих, а потім зліплювати?

Ось цим принчипово різниться український форум від російських, тут є діалог:-).
Спробую по максимуму описати:
1. Що я роблю? Створюю звіт для заключених договорів в розрізі компаній та продуктів
2. Як проводиться вибірка? Є сторінка на якій виводяться всі договори і останнім стовпцем іде checkbox де value=agreementId
3. Що передається? Основною є таблиця з договорами agreements.Як вже зрозуміло id в таблиці agreements і є value checkbox. Методом $_POST я закидаю масив в цикл де починає проводити наступні маніпуляції
4.Які маніпуляції? В циклі я витягую дані по договору з таблиці agreements. З цієї таблиці мені потрібен стовпчик productId WHERE id = agreementId. Взявши productId я мушу зрозуміти якій компанії належить даний продукт і відповідно роблю запит в таблицю products звідки беру companyId .
5. Інші. Як видно з усього вище викладеного ми маємо наприклад 90 договорів, які укладені наприклад на 3 компанії.Доприкладу:
Компанія 1 уклала 30 договорів з них 10 договорів мають ідентифікатор продукту productId = 1,10 договорів productId = 2 і 30 договорів productId = 3. Відповідно якщо це буде компанія 2 то ідентифікатори вже будуть інші.
Ось десь так виглядає задум. Мало би бути щось схоже на це:
$ar[$company['id']][][$product['id']][] = $agreement['id']
але виникає проблема як потім цей дурдом в циклі розкласти по ідентифікаторам

7

Re: Масив

Я, може, туплю, але можете уточнити, що означає "звіт для укладених договорів в розрізі компаній та продуктів"? Це буде таблиця

Угода | Компанія | Продукт

чи, навпаки,

Компанія1
   Угода11 - Продукт11, Угода12 - Продукт12, Угода13 - Продукт13
Компанія2
   Угода21 - Продукт21, Угода22 - Продукт22, Угода23 - Продукт23
Продукт1
   Угода 11 - Компанія 1, Угода 12 - Компанія 1, Угода 23 - Компанія2

Чи ще якось?
І які є таблиці, як вони пов'язані? Я ще раз кажу - один складний запит краще за 20 простих у циклі, БД для того і придумали, щоб потім складні цикли не ганяти.

Подякували: leofun011

8 Востаннє редагувалося Intrerio (04.11.2019 23:05:14)

Re: Масив

Ось так:
Компанія 1
     Продукт 1
           Договір1
           Договір 2
КОмпанія 2
     Продукт3
          Договір 10
          Договір 20

Пояснюю по звіту. Є продані послуги різних компаній. Кожна послуга це окремий договір. Договір відноситься до якогось продукту. От мені треба написати такий скрипт в якому я передаю купу ідентифікаторів договорів, а скрипт розкладе це по поличкам, а саме по компаніям і продуктам відносно компаній

9 Востаннє редагувалося koala (04.11.2019 23:22:04)

Re: Масив

SQL приблизно такий:

SELECT Company.Name as Company, Product.Name as Product, Agreement.Number as Agreement
    FROM Company INNER JOIN Agreement ON Company.ID == Agreement.CompanyID
                 INNER JOIN Product ON Product.ID == Agreement.CompanyID
    WHERE Agreement.ID IN ( agreementId1, agreementId2, ...)

Список в дужках можна отримати за допомогою

join(",",$_POST['agreementId'])

Тепер - як обробляти результат (припустимо, його перегнали в масив, хоча краще прямо з ресурсу через fetch_assoc витягати)

$old_company = NULL;
$old_product = NULL;
for($i=0;$i<count($result);++$i) //чи while($row = $result->fetch_assoc()) {
{
  $row = $result[$i];  
  if($row['Company']!=$old_company) {
    $old_company = $row['Company'];
    $old_product = NULL;
    //створюємо новий рядок про компанію
  }
  if($row['Product']!=$old_product) {
    $old_product = $row['Product'];
    //створюємо новий рядок про продукт
  }
  //стоворюємо новий рядок про $row['Agreement']
}

Звісно, конкретні назви полів ви маєте краще знати.

Подякували: flatliner, leofun012

10

Re: Масив

koala написав:

SQL приблизно такий:

SELECT Company.Name as Company, Product.Name as Product, Agreement.Number as Agreement
    FROM Company INNER JOIN Agreement ON Company.ID == Agreement.CompanyID
                 INNER JOIN Product ON Product.ID == Agreement.CompanyID
    WHERE Agreement.ID IN ( agreementId1, agreementId2, ...)

Список в дужках можна отримати за допомогою

join(",",$_POST['agreementId'])

Тепер - як обробляти результат (припустимо, його перегнали в масив, хоча краще прямо з ресурсу через fetch_assoc витягати)

$old_company = NULL;
$old_product = NULL;
for($i=0;$i<count($result);++$i) //чи while($row = $result->fetch_assoc()) {
{
  $row = $result[$i];  
  if($row['Company']!=$old_company) {
    $old_company = $row['Company'];
    $old_product = NULL;
    //створюємо новий рядок про компанію
  }
  if($row['Product']!=$old_product) {
    $old_product = $row['Product'];
    //створюємо новий рядок про продукт
  }
  //стоворюємо новий рядок про $row['Agreement']
}

Звісно, конкретні назви полів ви маєте краще знати.

Ваш варіант гарний і запит швидше буде оброблено, ніж мої три і це факт. Проте цикл виведе змінні, якщо додати перед = ще крупку .= то буде набір рядків, але в моєму випадку потрібно власне створити массив в якому буде зберігатись ієрархія
Компанія
      Продукт
            Договір
Після цього як я розкладу все по поличкам мені треба створити відповідний запис в БД, що буде означати ідентифікатор звіту і на базі якого буде згенеровано xls і pdf файл відповідними бібліотеками. Я от зараз ніби прийшов вже до якогось рішення, але всеодно воно не ідеальне. Поки ще модифіковую. Стосовно Вашого прикладу SQL запиту то погоджуюсь на всі 100% що він оптимальніший, ніж викликати три різні запити і витягувати всі поля.

11 Востаннє редагувалося Intrerio (04.11.2019 23:47:41)

Re: Масив

if(isset($_POST['create'])){
            for($i=0;$i<count($_POST['agreementId']);$i++){
                $agreement = Agreements::getAgreementById($_POST['agreementId'][$i]);
                $product = Products::getProductById($agreement['product_id']);
                $company = Company::getCompanyById($product['company_id']);
                $ar['companyId'][$company['id']]['id'] = $company['id'];    
                $ar['companyId'][$company['id']]['productId'][$product['id']]['id'] = $product['id']; 
                $ar['companyId'][$company['id']]['productId'][$product['id']]['agreements'][$agreement['id']] = $agreement['id']; 
            }
        }

Цикл який формує масив який мені потрібен ось такий

$arr = array();
        $i = 0;
        foreach ($ar['companyId'] as $c){
            $arr[$i]['companyId'] = $c['id'];
            foreach ($c['productId'] as $g){
                $arr[$i]['products'][] = $g;
                
            }
            $i++;
        }

Покищо прийшов до такого вигляду. Зараз ще заміную запит в БД на один і може щось в процесі підкорегую. До кращого варіанту я поки прийти не зміг

12

Re: Масив

Ну гаразд, тоді замість нових рядків додавайте інформацію в масив. Тільки він буде аж ніяк не асоціативний - ви ж самі писали щось про $ar[$company['id']][] - от пусті дужки в кінці показують, що масив не асоціативний. І доведеться розглядати всюди по два випадки - коли масив-елемент масиву верхнього рівня уже створений і коли його ще немає.

Подякували: Intrerio1

13

Re: Масив

koala написав:

Ну гаразд, тоді замість нових рядків додавайте інформацію в масив. Тільки він буде аж ніяк не асоціативний - ви ж самі писали щось про $ar[$company['id']][] - от пусті дужки в кінці показують, що масив не асоціативний. І доведеться розглядати всюди по два випадки - коли масив-елемент масиву верхнього рівня уже створений і коли його ще немає.

Вцілому варіант,який вийшов робочий. Шкода що дуже громісткий. Люблю, щоб все було компактно, а тут не зовсім вийшло компактно. Сподіваюсь після досягнення поставленої цілі все ж повернусь і перероблю в більш гарний вигляд. Дякую за допомогу

14

Re: Масив

Може, покажете, що вийшло?

15

Re: Масив

koala написав:

Може, покажете, що вийшло?

Якраз дописую загальний код і скоро викину. Щоправда SQL запит буду завтра змінювати

16 Востаннє редагувалося flatliner (05.11.2019 02:20:18)

Re: Масив

Це випадок, за який люблю ORM'и... на FuelPHP це було б щось на кшталт такого:

$results = \Model_Company::query()
    ->related('products')
    ->related('products.agreements')
    ->where('products.agreements.id', 'IN', \Input::post('agreementId', []))
    ->get();

На виході ми вже отримаєм масив ORM-об'єктів, в яких відповідні поля будуть масивами вкладених ORM-об'єктів і т. д. Так, за ці зручності є певна розплата - витрати на гідрацію... зате як зручно писати код! Пізніше вузькі місця можна переписати з використанням білдера або навіть чистих SQL-запитів, але для більшості випадків робота з ORM задовольняє.