Zen Cart Logo
Forums / Bug Reports / Change to $db Move(0)/MoveNext() behavior breaks plugins

Change to $db Move(0)/MoveNext() behavior breaks plugins

Views: 1,784

Results 1 to 15 of 15
30 Mar 2016, 5:46 PM
#1
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Change to $db Move(0)/MoveNext() behavior breaks plugins

In Zen Cart 1.5.5, someone noticed that when trying to reset a query (using $the_query->Move (0)) didn't work, so they "fixed" the behavior.

Unfortunately, that fix now breaks existing plugins (a couple of mine, that I'll need to hunt up, and others) which have "known" that to reset a query you had to:

$the_query->Move (0);
$the_query->MoveNext ();

to accomplish that feat. Now, any plugin that requires a query-reset is going to have to check the Zen Cart version to see whether that MoveNext () call is required.

I put together a teeny script to illustrate the issue:

<?php
include ('includes/application_top.php');
$list = $db->Execute ("SELECT * FROM " . TABLE_ORDERS_STATUS . " ORDER BY orders_status_id ASC");
echo "First pass iteration:<br />";
while (!$list->EOF) {
    echo sprintf ("Orders status id = %u, name = %s<br />", $list->fields['orders_status_id'], $list->fields['orders_status_name']);
    $list->MoveNext ();
}
echo "<br />Second pass iteration:<br />";
$list->Move (0);
$list->MoveNext ();
while (!$list->EOF) {
    echo sprintf ("Orders status id = %u, name = %s<br />", $list->fields['orders_status_id'], $list->fields['orders_status_name']);
    $list->MoveNext ();
}

and then ran that script on a "fresh" Zen Cart 1.5.4 installation, yielding:

First pass iteration:
Orders status id = 1, name = Pending
Orders status id = 2, name = Processing
Orders status id = 3, name = Shipped
Orders status id = 4, name = Update

Second pass iteration:
Orders status id = 1, name = Pending
Orders status id = 2, name = Processing
Orders status id = 3, name = Shipped
Orders status id = 4, name = Update

That same script, run on a "fresh" Zen Cart 1.5.5 (3-29) installation yields:

First pass iteration:
Orders status id = 1, name = Pending
Orders status id = 2, name = Processing
Orders status id = 3, name = Delivered
Orders status id = 4, name = Update

Second pass iteration:
Orders status id = 2, name = Processing
Orders status id = 3, name = Delivered
Orders status id = 4, name = Update

See how the 2nd-pass output is missing the first orders-status record? That's what's going to happen to all those plugins that were just "doing the right thing" when they're run without change on Zen Cart 1.5.5.

Please note that I'm not asking for the behavior to be modified, since there are now Zen Cart 1.5.5 installations with this functionality and it will just further compound the issue if the 1.5.5 behavior is changed mid-stream. I'm posting to let other plugin authors know that they're going to need to check their plugins, too.

30 Mar 2016, 6:06 PM
#2
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Have you tried using:

$blah->rewind();
30 Mar 2016, 6:08 PM
#3
drbyte avatar

drbyte

Sensei

Join Date:
Jan 2004
Posts:
63,513
Plugin Contributions:
176

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

You're right. But the real bug is that the Move(0) should never have needed to be followed by MoveNext().
I think my advice was always to never rely on using Move(0) because I knew this bug existed but hadn't been fixed.
Regardless, you're right: plugins that relied on using Move(0) will have unexpected results.

The better way, moving forward, is to use the Iterator approach instead of the old "while(!EOF) { // work; MoveNext() }" approach.

OLD WAY:

$result = $db->Execute($sql);
while (!$result->EOF) { 
  $data = $result->fields['filename'];
  //foo
  $result->MoveNext();
}

NEW WAY:

$result = $db->Execute($sql);
foreach ($result as $row) {
  $bar = $row['fieldname'];
}
// To reset and loop again, use:
reset($result);

Note that with the foreach() approach, MoveNext() is dropped altogether.
And reset() is used instead of Move(0) (although Move(0) will indeed do the same as reset() now)

I suppose for compatibility, you could try testing whether method_exists($result, 'rewind') to determine if your plugin needs to add a MoveNext() after the old Move(0).

30 Mar 2016, 8:25 PM
#4
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Ajeh:

Have you tried using:

$blah->rewind();

Nope, that function was added in Zen Cart 1.5.5.
30 Mar 2016, 8:33 PM
#5
ajeh avatar

ajeh

Oba-san

Join Date:
Sep 2003
Location:
Ohio
Posts:
62,757
Plugin Contributions:
1

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Sorry since this was marked v155 I thought you were looking for a v155 method ... :lookaroun

DrByte's method works any which way ...

30 Mar 2016, 11:01 PM
#6
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

DrByte:

You're right. But the real bug is that the Move(0) should never have needed to be followed by MoveNext().
I think my advice was always to never rely on using Move(0) because I knew this bug existed but hadn't been fixed.
Regardless, you're right: plugins that relied on using Move(0) will have unexpected results.

The better way, moving forward, is to use the Iterator approach instead of the old "while(!EOF) { // work; MoveNext() }" approach.

OLD WAY:

$result = $db->Execute($sql);
while (!$result->EOF) {
$data = $result->fields['filename'];
//foo
$result->MoveNext();
}

> 
> NEW WAY:
> ```
$result = $db->Execute($sql);
foreach ($result as $row) {
  $bar = $row['fieldname'];
}
// To reset and loop again, use:
reset($result);

Note that with the foreach() approach, MoveNext() is dropped altogether.
And reset() is used instead of Move(0) (although Move(0) will indeed do the same as reset() now)

I suppose for compatibility, you could try testing whether method_exists($result, 'rewind') to determine if your plugin needs to add a MoveNext() after the old Move(0).
I'm thinking that I'll just check for earlier than Zen Cart v1.5.5 to issue the additional MoveNext ()

8 Apr 2016, 11:51 PM
#7
rbarbour avatar

rbarbour

Totally Zenned

Join Date:
Feb 2010
Posts:
2,159
Plugin Contributions:
10

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Maybe I'm a little thick here,

I'm creating new and (updating) old plugins for 1.5.5 and the "NEW WAY" isn't working for $db->ExecuteRandomMulti($sql), when a constant ", MAX_DISPLAY" is set.

What am I missing?

DrByte:

You're right. But the real bug is that the Move(0) should never have needed to be followed by MoveNext().
I think my advice was always to never rely on using Move(0) because I knew this bug existed but hadn't been fixed.
Regardless, you're right: plugins that relied on using Move(0) will have unexpected results.

The better way, moving forward, is to use the Iterator approach instead of the old "while(!EOF) { // work; MoveNext() }" approach.

OLD WAY:

$result = $db->Execute($sql);
while (!$result->EOF) {
$data = $result->fields['filename'];
//foo
$result->MoveNext();
}

> 
> NEW WAY:
> ```
$result = $db->Execute($sql);
foreach ($result as $row) {
  $bar = $row['fieldname'];
}
// To reset and loop again, use:
reset($result);

Note that with the foreach() approach, MoveNext() is dropped altogether.
And reset() is used instead of Move(0) (although Move(0) will indeed do the same as reset() now)

I suppose for compatibility, you could try testing whether method_exists($result, 'rewind') to determine if your plugin needs to add a MoveNext() after the old Move(0).

9 Apr 2016, 11:28 AM
#8
mc12345678 avatar

mc12345678

Totally Zenned

Join Date:
Jul 2012
Posts:
16,908
Plugin Contributions:
2

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

rbarbour:

Maybe I'm a little thick here,

I'm creating new and (updating) old plugins for 1.5.5 and the "NEW WAY" isn't working for $db->ExecuteRandomMulti($sql), when a constant ", MAX_DISPLAY" is set.

What am I missing?

Haven't tested this condition, but by code review, MAX_DISPLAY doesn't appear to be an existing ZC 1.5.5 constant, does it work if a number is briefly put in place of the constant? If so, then it would appear that the constant is not defined prior to the execution of ExecuteRandomMulti sql.

Does the same problem occur if instead of ExecuteRandomMulti you try a standard Execute? (Ie. basically trying both types of execution to validate that the "new method" (Assume referring to use of foreach on an array instead of while(!$obj->EOF) type loop) works).

9 Apr 2016, 3:42 PM
#9
rbarbour avatar

rbarbour

Totally Zenned

Join Date:
Feb 2010
Posts:
2,159
Plugin Contributions:
10

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

"MAX_DISPLAY" is not existing, was an example per se.

I guess better examples would be the center-box "loops".

$db->ExecuteRandomMulti($specials_index_query, MAX_DISPLAY_SPECIAL_PRODUCTS_INDEX);
$db->ExecuteRandomMulti($new_products_query, MAX_DISPLAY_NEW_PRODUCTS);
$db->ExecuteRandomMulti($featured_products_query, MAX_DISPLAY_SEARCH_RESULTS_FEATURED);
$db->ExecuteRandomMulti(sprintf(SQL_ALSO_PURCHASED, (int)$_GET['products_id'], (int)$_GET['products_id']), MAX_DISPLAY_ALSO_PURCHASED);

I'm mainly updating plugins for 1.5.5 but using the "NEW" way doesn't respect the constant. Yes the standard execute works but you no longer get random products on page reload or revisit.

mc12345678:

Haven't tested this condition, but by code review, MAX_DISPLAY doesn't appear to be an existing ZC 1.5.5 constant, does it work if a number is briefly put in place of the constant? If so, then it would appear that the constant is not defined prior to the execution of ExecuteRandomMulti sql.

Does the same problem occur if instead of ExecuteRandomMulti you try a standard Execute? (Ie. basically trying both types of execution to validate that the "new method" (Assume referring to use of foreach on an array instead of while(!$obj->EOF) type loop) works).

9 Apr 2016, 4:08 PM
#10
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

rbarbour:

... I'm mainly updating plugins for 1.5.5 but using the "NEW" way doesn't respect the constant ...
Just a note to readers of this thread: Using the "new" way will ***only ***work for plugins that support ***only ***Zen Cart 1.5.5 or later since prior Zen Cart versions don't know the "new" way!

9 Apr 2016, 4:11 PM
#11
rbarbour avatar

rbarbour

Totally Zenned

Join Date:
Feb 2010
Posts:
2,159
Plugin Contributions:
10

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Very true :smile:

Any ideas here Cindy?

lat9:

Just a note to readers of this thread: Using the "new" way will ***only ***work for plugins that support ***only ***Zen Cart 1.5.5 or later since prior Zen Cart versions don't know the "new" way!

9 Apr 2016, 4:32 PM
#12
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

FWIW, I'm sticking with the "old" way for any of my plugins that support ZC1.5.5 and earlier; I'll update to use the "new" method ***only ***for plugins that I've targeted for Zen Cart 1.5.5 and later.

Otherwise, either the code will get too convoluted with the if-then-elsing around the new/old methods or the plugin installation procedure will get over-complicated with if-then-elsing around the target Zen Cart version.

12 Apr 2016, 5:51 AM
#13
drbyte avatar

drbyte

Sensei

Join Date:
Jan 2004
Posts:
63,513
Plugin Contributions:
176

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

rbarbour:

Maybe I'm a little thick here,

I'm creating new and (updating) old plugins for 1.5.5 and the "NEW WAY" isn't working for $db->ExecuteRandomMulti($sql), when a constant ", MAX_DISPLAY" is set.

What am I missing?
Which plugins are using ExecuteRandomMulti?

12 Apr 2016, 12:50 PM
#14
lat9 avatar

lat9

Administrator

Join Date:
Sep 2009
Location:
Stuart, FL
Posts:
14,097
Plugin Contributions:
56

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

For one, my jQuery Scrolling Sideboxes does: https://www.zen-cart.com/downloads.php?do=file&id=1909. Not that I'm planning on converting it to the "new method" at this time.

12 Apr 2016, 1:47 PM
#15
rbarbour avatar

rbarbour

Totally Zenned

Join Date:
Feb 2010
Posts:
2,159
Plugin Contributions:
10

Re: Change to $db Move(0)/MoveNext() behavior breaks plugins

Flexible Center-boxes
Flexible Side-boxes

These 2 plugins get incorporated in almost every template knowingly or not simply for the "add to cart/more info" functions for center-boxes and side-boxes.

User experience and overall functionality is make or break and IMO "at least" the "add to cart/more info" functions should be part of the core for both center and side boxes.

DrByte:

Which plugins are using ExecuteRandomMulti?