PHP - Найдите проблему в этом foreach? - PullRequest
1 голос
/ 07 августа 2011

Я создаю простую корзину заказов.

По сути, пользователь щелкает по порядку, идентификатор продукта добавляется в переменную сеанса ($ order) в виде массива. При просмотре «корзины» происходит проверка, где, если значение в переменной сеанса равно идентификатору конкретной строки в таблице mysql, эта конкретная строка возвращается как заказанный элемент. Для каждого значения в переменной сеанса этот процесс должен повториться.

Вот фрагмент кода, с которым я борюсь:

foreach ($order as $item) 
{
    while($row = mysql_fetch_assoc($productsSql))
    {
         $itId = $row['id'];
         $itDesc = $row['desc'];
         $itPrice1 = $row['price1'];
         if ($item == $itId) 
        {
        $pageContent .= '
                <tr>
                    <td>'.$itDesc.'</td>
                    <td>
                        R'.number_format($itPrice1, 2).'
                    </td>
                </tr>
';      
        }
    }   
}

Переменная «$ orders» такая:

session_start();
if (!isset($_SESSION['order']))
{
$_SESSION['order'] = array();
}

Может кто-нибудь заметить какие-либо проблемы с этим?

$productsQuery = 'SELECT `id`, `refCode`, `desc`, `pack`, `measure`, `quantity`, `deptCode`, `taxable`, `price1`, `price2`, `crdCode`, `cost1`, `cost2` FROM `products` ORDER BY `desc` ';
$productsSql = mysql_query($productsQuery) or die(mysql_error());`

Ответы [ 3 ]

3 голосов
/ 07 августа 2011
while($row = mysql_fetch_assoc($productsSql))

Это не будет воспроизводиться каждые $item, поэтому сохраните строки в массиве перед foreach и замените это while на foreach.

2 голосов
/ 08 августа 2011

Вы не указали содержимое $productsSql, но строка, содержащая его, выглядит неправильно.

Если $productsSql содержит код SQL, он вообще не будет работать, поскольку для mysql_fetch_assoc() требуетсяресурс базы данных.Чтобы получить ресурс, вам нужно вызвать mysql_query() с вашим кодом SQL.

Если вы вызвали mysql_query() вне кода, который вы цитировали, и $productsSql содержит результирующий ресурс, этовсе еще неправильно, потому что вы просматриваете результаты базы данных несколько раз (из-за цикла foreach), но без сброса или запроса.

В результате после первой итерации foreach, цикл while будет проходить через все результаты в запросе к базе данных и будет установлен в конец набора результатов.Возврат к вершине кода не изменит позиции набора результатов, поэтому при первой попытке вызова mysql_fetch_assoc() во втором цикле будет сказано «Я уже закончил», и ничего не произойдет.Случается.

Если вы хотите, чтобы один и тот же набор результатов обрабатывался на каждой итерации цикла foreach, вам необходимо сбросить указатель БД перед началом цикла while.Это можно сделать с помощью функции mysql_data_seek() .

Это, вероятно, позволит достичь того, что вы хотите, с помощью предоставленного вами кода.

Однако это может не произойтибыть наиболее эффективным способом достижения желаемого результата.К сожалению, трудно быть более конкретным, как улучшить его, не видя больше вашего кода (в частности, SQL-запрос и больше вашей структуры данных).

[EDIT] После того, как OP добавил SQL-запросНа вопрос, мы можем более четко увидеть, каков наилучший ход действий.

Быстрое и грязное решение действительно заключается в использовании mysql_data_seek(), как я объяснил выше (и как показано в коде @Phoenix), но хотя это заставит программу работать, она будет очень неэффективной, особенно когда в базу данных добавляется больше продуктов.

На самом деле требуется полное изменение кода, начиная с запроса SQLсам по себе.

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

SELECT <lots of fields> FROM products WHERE id IN(5,7,9,<etc>)

Это легко создать, поскольку $orders выглядит как массив идентификаторов элементов, поэтому выможно просто использовать implode(',',$orders), чтобы составить список идентификаторов, подходящих для предложения WHERE.(хотя вы должны быть абсолютно уверены, что все они являются числовыми идентификаторами, потому что что-то еще может нарушить SQL-запрос; если вы не уверены, SQL должен сначала их избежать).

Как только выПолучив этот список, лучше всего загрузить значения БД в массив памяти, а затем использовать цикл foreach($order), чтобы получить соответствующий элемент массива.

Таким образом, ваш конечный код будет выглядеть примерно так:

$productsQuery = 'SELECT `id`, `refCode`, `desc`, `pack`, `measure`, `quantity`, `deptCode`, `taxable`, `price1`, `price2`, `crdCode`, `cost1`, `cost2` FROM `products` WHERE id IN('.implode(',',$orders).')';
$productsSql = mysql_query($productsQuery) or die(mysql_error());`

$data = array();
while($row = mysql_fetch_assoc($productsSql)) {
    $data[$row['id']] = $row;
}

foreach($order as $item) {
   $pageContent .= '
            <tr>
                <td>'.$row[$item]['desc'].'</td>
                <td>
                    R'.number_format($row[$item]['price'], 2).'
                </td>
            </tr>
    ';
}
2 голосов
/ 07 августа 2011

попробуйте

mysql_data_seek ($ productsSql, 0);

foreach ($order as $item) 
{
mysql_data_seek( $productsSql, 0);  //<- this line, to reset the pointer for every EACH.
    while($row = mysql_fetch_assoc($productsSql))
    {
         $itId = $row['id'];
         $itDesc = $row['desc'];
         $itPrice1 = $row['price1'];
         if ($item == $itId) 
        {
        $pageContent .= '
                <tr>
                    <td>'.$itDesc.'</td>
                    <td>
                        R'.number_format($itPrice1, 2).'
                    </td>
                </tr>
';      
        }
    }   
}

надеюсь, что помогает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...