muzzer Posted September 13, 2012 Share Posted September 13, 2012 I'm building my first PW site (lovin this system) and working on a custom shopping cart at present. But I'm having a problem getting image resizing to work using AJAX. I have a function which is called in different circumstances both normally and via AJAX function generateCart( $page, $pages, $config ) { $purchases = $pages->get( '/wcart/sprees/' . session_id() . '/' )->find( 'template=wcart-product-page' ); foreach( $purchases as $purchase ) { $product = $pages->get( $purchase->wcart_product_id ); $productImage = $product->wcart_image->size( 80, 60 ); .... } } Calling from AJAX fails with the error: WireException: Method Pageimages::size does not exist or is not callable in this context [C:\wamp\www\spv\wire\core\Wire.php:232] The function call normally is : echo generateCart( $page, $pages, $config ); That's fine, works as you would expect. But from ajax: if(wire('config')->ajax) echo generateCart( wire( 'page' ), wire( 'pages' ), wire( 'config' )); and it throws the error. What's going on, is something not visible here that needs to be? In case you're wondering 'wcart_image' is a field of type image. Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 WireException: Method Pageimages::size does not exist or is not callable in this context Looks like you need to threat the image(s) as array adding a ->first()->size() $productImage = $product->wcart_image->first()->size( 80, 60 ); Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 Looks like you need to threat the image(s) as array adding a ->first()->size() $productImage = $product->wcart_image->first()->size( 80, 60 ); Thanks but doing so produces: Fatal error: Call to a member function size() on a non-object. $product->wcart_image is not an array according to is_array($product->wcart_image) Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 It would not be a normal php array but a WireArray with image objects. Where is your function located? What is the setup exactly there? Edit: And from where are you doing the function call? Link to comment Share on other sites More sharing options...
ryan Posted September 13, 2012 Share Posted September 13, 2012 Soma is right in his suggestion, but chances are that your "non-object" error came because you tried to do it on a page with no images. Thus, first() returned null and you tried to call size() on a non-object. So you'd want to do something like this instead: $productImage = $product->wcart_image->first(); if($productImage) $productImage = $productImage->size(80,60); or this if(count($product->wcart_image)) { $productImage = $product->wcart_image->first()->size(80,60); } Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 Thanks Ryan. Tried your suggestion, resulting in: E_USER_ERROR: Exception: Method Pageimage::first does not exist or is not callable in this context The generateCart function is called on a "show cart" page to generate the shopping cart table. There is definately an image for the product. It's called again (but with parameters passed in wire('var') format) from ajax when the number of items is adjusted (from an input field in the cart table), so nothing has changed at this point (images etc) other than the number of items in the cart. Essentially what it appears to me is there is something missing when the function is called via ajax as it's exactly the same code in every respect other than the call method. It's doing my head in! Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 Further: function generateCart( $page, $pages, $config ) { $purchases = $pages->get( '/wcart/sprees/' . session_id() . '/' )->find( 'template=wcart-product-page' ); foreach( $purchases as $purchase ) { $product = $pages->get( $purchase->wcart_product_id ); debug( $product->wcart_image ); $productImage = $product->wcart_image; debug($productImage); if($productImage) $productImage = $productImage->size(80,60); .... } } The two debug lines output a string 'bioflow-dog-collars.jpg' (not an array). Output of both is the same (as you would expect). Changing $productImage = $product->wcart_image; to $productImage = $product->wcart_image->first(); produces the error. Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 Hey Soma, sorry, I completely didn't see your reply; It would not be a normal php array but a WireArray with image objects. What does this mean in practice exactly? I'm still trying to get my head around this. How would it be accessed (compared to a normal php array)? Where is your function located? What is the setup exactly there? Edit: And from where are you doing the function call? The function is located in /site/wdnzScripts/wcart.inc.php. When called from ajax this file is called directly and the function call is if(wire('config')->ajax) echo generateCart( wire( 'page' ), wire( 'pages' ), wire( 'config' )); and is located directly above the function. When called normally the function call is in a template: include_once( $config->paths->root . 'site/wdnzScripts/wcart.inc.php' ); echo generateCart( $page, $pages, $config ); I'm obviously missing something obvious here. Both you and Ryan say it should be an array so thats as good as gospel for me, it should be an array. But whatever way I look at it it appears to be a string! Link to comment Share on other sites More sharing options...
Adam Kiss Posted September 13, 2012 Share Posted September 13, 2012 What does this output: echo gettype($product->wcart_image); Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 I just ran a little test with latest PW and I have no problems requesting a special "/ajax/" page with a template with more or less your example code. Returning a scaled image string, doesn't matter from where. So I can't reproduce it. Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 What does this output: echo gettype($product->wcart_image); > object Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 I'm still not sure when reading your setup and where is what. It can be confusing lol Just think of it as a special type of array that has certain methods depending on type etc. Usually in templates, $page->image as the name would suggest it is a single image field (field setting to max=1), so it would be directly the one image object. If you have a "images" field, and set it to max=0, so no limit, the field will be an array in the templates files and you have to iterate through them or directly access it by some of these methods WireArray's have. So ->first() or ->eq(2) would give you the image object. Now in certain cases this array, single object behaviour is only on template and admin level. Technically it's always an WireArray, but the system has a output formatting that will take care for that. So if you turn of outputformatting you would always have to use ->first() to access the one item in the array. So it's possible that this is the case, but it's obviously not, or I'm still not sure what causes the problem in your case. Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 The function is located in /site/wdnzScripts/wcart.inc.php. When called from ajax this file is called directly and the function call is if(wire('config')->ajax) echo generateCart( wire( 'page' ), wire( 'pages' ), wire( 'config' )); Call it directly? You can't put a script in the /site/yourdir/.. folder an call it directly via ajax, that will give access denied by htaccess. The function you write, that is not an ajax call, an ajax call is made via javascript. So can't say for sure I understand. include_once( $config->paths->root . 'site/wdnzScripts/wcart.inc.php' ); echo generateCart( $page, $pages, $config ); I'm obviously missing something obvious here. Both you and Ryan say it should be an array so thats as good as gospel for me, it should be an array. But whatever way I look at it it appears to be a string! But I'm maybe also missing the obvious or still don't get your code flow, for example where and how do you do the ajax request? And where are you seeing the error? Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 Soma, thanks for your time on this. Sorry I seems to have confused you as to how it's all set up, so heres a fuller version of the code: ajax call: $('.numberAdjustment').live('change', function(){ var $this = $(this) var btnText = $(this).html(); var inputVal = $(this).val(); var inputId = $(this).attr('name'); var serial = "inputId=" + inputId + "&inputVal=" + inputVal; $.ajax({ url: location.protocol + '//' + location.host + '/site/wdnzScripts/wcart.inc.php', type: "post", data: serial, success: function(responseText){ $('#cart').fadeOut(500, function() { $('#cart').css('display', 'none'); $('#cart').html(responseText); $('#cart').fadeIn(500); showNotif('<p>Your cart contents have been updated.</p>', $this, btnText ); }); }, error: function(){ alert("Oops, there was an error adjusting the cart contents"); } }); }); that simply detects when the input with class 'numberAdjust' in the cart table is altered and calls out troublesome script, which updates the number of the product in the cart and returns the updated cart table HTML. It then fades the old cart table out and fades the updated version in. No problems there. The script /site/wdnzScripts/wcart.inc.php: <?php include_once( $_SERVER['DOCUMENT_ROOT'] . $_SERVER['HTTP_HOST'] . '/index.php' ); // bootstrap PW // ajax calls if(wire('config')->ajax) { // set number of units of a product in the cart if( isset( $_POST['inputId'] ) AND isset( $_POST['inputVal'] )) { $id = str_replace( 'units_id', '', $_POST['inputId'] ); alterProductPurchase( wire( 'pages' ), wire( 'input' ), wire( 'config' ), $id ); echo generateCart( wire( 'pages' ), wire( 'config' )); } return; } // alter number of units for an existing product in the cart. Called from the units input in the cart table function alterProductPurchase( $pages, $input, $config, $id ) { // check if the page with this exact product already exists, if so add to it, else create $purchase = $pages->get( '/wcart/sprees/' . session_id() . '/' )->find( 'template=wcart-product-page,id=' . $id ); if( $purchase[0] ) { if( $input->post['inputVal'] == 0 ) { // delete product from cart $pages->delete( $purchase[0] ); } else { // exact product exists for this customer, so add the new purchase's units $purchase = $purchase[0]; // get first record returned $purchase->wcart_product_units = $input->post['inputVal']; $purchase->setOutputFormatting( false ); $purchase->save(); } } } function generateCart( $pages, $config ) { $purchases = $pages->get( '/wcart/sprees/' . session_id() . '/' )->find( 'template=wcart-product-page' ); $cartHtml = '<table id="cart" class="table table-striped table-bordered table-hover"><thead><tr><th>id</th><th>title</th><th>colour</th><th>size</th><th>number</th><th></th><th></th></tr></thead><tbody>'; foreach( $purchases as $purchase ) { $product = $pages->get( $purchase->wcart_product_id ); $productImage = $product->wcart_image; debug( 'prior to image resize' ); if($productImage) $productImage = $productImage->size(80,60); //THE ERROR OUTPUTS BETWEEN THESE TO DEBUG CALLS ('debug' is a chrome/lagger function) debug( 'after image resize' ); $cartHtml .= '<tr>'; $cartHtml .= '<td><a href="' . $product->url . '"><img src="' . $productImage->url . '" width="80" alt="" /></a></td>'; $cartHtml .= '<td>' . $product->title . '</td>'; $cartHtml .= '<td>' . $purchase->wcart_product_colour . '</td>'; $cartHtml .= '<td>' . $purchase->wcart_product_size . '</td>'; $cartHtml .= '<td><input type="text"class="numberAdjustment input-mini" name="units_id' . $purchase->id . '" value="' . $purchase->wcart_product_units . '"></td>'; $cartHtml .= '<td><button class="removeLink btn btn-mini btn-danger" id="remove_id' . $purchase->id . '"type="button">Remove</button></td>'; $cartHtml .= '<td></td></tr>'; } $cartHtml .= '</tbody></table>'; return $cartHtml; } ?> Note: If I remove the image resizing lines and the script/ajax works beautifully. Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 I see, still even if I rebuild yours and also include the bootstrap, I can call it directly via a ajax jquery script. And I can reproduce that what we first answered. Even if it's a single image field you have to call it with $p->image->first()->sie Now looking again at the error code "Pageimages::size" That's exactly why me and Ryan suggested to try the ->first() method. And my tests show exactly this behaviour. Works fine here so can't really help and don't see anything wrong that sticks out. I have a /site/ajax/ajax.inc.php include_once( $_SERVER['DOCUMENT_ROOT'] . "/index.php"); function generateCart( $pages, $config ) { $p = $pages->get("/about/"); $img = $p->image->first()->size(100,120); return $img->url; } if(wire('config')->ajax){ echo generateCart( wire("pages"), wire("config") ); } And when I call it directly from a pw page <script> $.ajax({ url: "/site/ajax/ajax.inc.php", success: function(data){ $('#bodycopy').html(data); } }); </script> I get this back /site/assets/files/1001/pastedgraphic-1.100x120.png And the image field "image" is limited to 1 max. So in a normal call in a PW page you only would do $page->image->size(100,0)->url Link to comment Share on other sites More sharing options...
Soma Posted September 13, 2012 Share Posted September 13, 2012 The only thing I see now to reproduce your fatal error ist writin ->first instead of ->first() This has come up so often it was clear from the beginning it has to do with it being and "Pageimages" WireArray instead of a single object of type "Pageimage". That's most likely when you directly request it and include the PW index.php. BTW do you also bootstrap that when doing normal function call when included? Because it's not necessary on a PW template file. SO you most likely have to also include a check for using first() or not depending if it's an ajax request or not. Link to comment Share on other sites More sharing options...
muzzer Posted September 13, 2012 Author Share Posted September 13, 2012 SO you most likely have to also include a check for using first() or not depending if it's an ajax request or not. You are right! I've altered it to read: if(wire('config')->ajax) $productImage = $product->wcart_image->first()->size(80,60); else $productImage = $product->wcart_image->size(80,60); and it's all go Still, I'm not sure I understand why this is so. Can someone explain exactly how wire('page') is different structurally to $page. This is one aspect of PW that has confused me from day dot. Thank you Soma for your awesome assistance. Much appreciated. Link to comment Share on other sites More sharing options...
Soma Posted September 14, 2012 Share Posted September 14, 2012 Well i thought i explained it already. In a bootstrap theres no page context thus no output formatting. Sent from mobile. Link to comment Share on other sites More sharing options...
elabx Posted November 29, 2016 Share Posted November 29, 2016 Bumping up this really old thread because I got into this issue, calling any resize functions on a single image field throws the exception mentioned previously, as if the object I am calling the resize function from, is of type Pageimages. Should this be the expected behaviour? I think it's really non intuitive that it happens only on AJAX calls. Maybe a server specs specific issue? Thanks for further clarification! Link to comment Share on other sites More sharing options...
Robin S Posted November 29, 2016 Share Posted November 29, 2016 @elabx, the unformatted value of an images field is always a WireArray. Having the value be a Pageimage for a single image field is the result of output formatting. I think what Soma is saying above is that output formatting is off when you bootstrap the PW index.php. So the issue doesn't occur because of an AJAX call, it occurs because of the bootstrapping. So solutions would be either: Just be aware that output formatting is off when bootstrapping PW and adjust your code accordingly In your AJAX call, load a normal PW page rather than a PHP file that bootstraps index.php 2 Link to comment Share on other sites More sharing options...
elabx Posted December 12, 2016 Share Posted December 12, 2016 I'm sorry I didn't read this correctly before, but to clarify I wasn't bootstraping the PW installation, it was a plain AJAX call to the same URL. Why I came back? I had a "similar" issue where I tried pulling some content via AJAX and when trying to use $user->isLoggedin(), the result always returned true. I moved that code to a custom module (and called $modules->get("CustomModule")->someFunction() ) , and it all worked just fine. Would this issue be related to output formatting too? Thanks for further help! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now