Jump to content

[SOLVED] Can't add image in certain situation


Harmen
 Share

Recommended Posts

Hi all,

Currently I'm developing a new feature for my module ImportPagesPrestashop. This module imports your categories, products and more from a prestashop database and implement that data in ProcessWire pages. I've made the following structure for this:

  1. Products (Parent Page which the user has to choose)
    1. Categories (implemented from the database)
      1. Products (Implemented from the database)

And inside of the product pages several fields for the specifications of the products, description, images and more.

So I've build a check inside of my module which doesn't allow you to first import the images and then the products or in another way, but you have to follow this route:

  1. Categories
  2. Products
  3. Specifications 
  4. Images

This is because the products require a category as their parent page and the specifications and images need a product page. 

Now I want to remove the check if you used this module before, so all pages you need are already there, you only need to update the pages. That's why I have done the following:

$parent = $this->parent;
if (!$parent->hasChildren()) {
	//if parent has no children, module isn't used before
	// set ranking in import
	// my code
}
if ($parent->hasChildren()){
	//module is used before, so parent has children
	//no ranking in import, any button can be clicked. No specific path required.
	//my code
}

So far so good. It works and I was happy with it, until I tried to import the images of the products. I encountered a error which says this:

Error: Call to a member function add() on a non-object (line 986 of / etc etc)

So I was like huh, why doesn't this work. I will explain how I perform the import of the images.

If the button is clicked, another function is called:

 if ($this->input->post->importimg) {
 	return $this->processForm51($form);
 }

so function ProcessForm 51 is called, below you can see this function:

protected function processForm51(inputfieldForm  $form){
	///... some code 
	$this->ImportImages(); //Function is called which performs the import of the images
	return $this->processFormMarkupImg($imgImported); //return after the import
}

This function links to the function that performs the import:

protected function importImages(){
	    // some code to get the images and store it in $pictures
		$pagesWithImages = wire("pages")->find("images_product.count>0"); //find pages with that field for the images
		foreach ($pagesWithImages as $product_page) {
			$product_page->images_product->removeAll(); // remove existing images
			$product_page->save();
		}

		foreach ($pictures as $picture) {
			$id_product = $picture['id_product'];
			$product_pages = wire("pages")->get("productid=$id_product"); //get the correct page so the images are placed in the correct product page
			// ensure output formatting is off
			$product_pages->of(false);
			$str_prlink = $picture['product_name']; 
			//make sure end of string ends with alphanumeric
			$image_name = preg_replace('/[^a-z0-9]+\Z/i', '', $str_prlink);
			$image_url = $picture['file_id'] . "/" . $image_name . '.jpg';
			$image_path = "http://www.website/" . $image_url;
			try {
           		$imgfield = $product_pages->images_product;
            		$imgfield->add($image_path); //add the images to the field
			} catch (Exception $e) {
			}
			$product_pages->save();
		}
	}

This should work because when I perfom this import WITH the ranking in import (first categories, 2nd products etc) it works! I don't get it why this gives an error WITHOUT the ranking in import. 

So that's why I am asking it over here, hopefully anyone knows how to solve this.

 

Thanks in advance,

~Harmen

Edited by Harmen
Solved
Link to comment
Share on other sites

Nothing jumps out at me. Things to confirm:

$imgfield = $product_pages->images_product;

Are you sure that returns an Object and not Null? 

Some other comments, by the ways...

45 minutes ago, Harmen said:

This is because the products require a category as their parent page and the specifications and images need a product page. 

Is this by your design or by necessity (i.e. Prestashop demands that). Normally, especially in cases where several products can share one or more categories, you want to have categories separated from the products (i..e not as their children).

// ensure output formatting is off
$product_pages->of(false);

This is not necessary here. Output formatting is always off in a module context.

if (!$parent->hasChildren()) {
}

That may not be very foolproof (could children have been manually deleted?). You can check using the module version instead, i.e. if version is less than x, do this, else do that. I can't find the exact syntax for it now but will edit this post later if I do.

Edit: grep version_compare under /wire/modules/ for more examples. Here's an example from a third-party module, changelog.

Edit 2: Arrgh. Scrap that. That's not it really; Hopefully someone will chime in. You should be able to compare versions of your modules programmatically though; I'm sure of it.

Edited by kongondo
module context stuff
  • Like 1
Link to comment
Share on other sites

17 minutes ago, kongondo said:

Are you sure that returns an Object and not Null? 

Yup, because with the ranking it works, so it has to return an object. I tried to store it in a var because 

$product_pages->images_product->add($image_path);

also didn't work.

17 minutes ago, kongondo said:

Is this by your design or by necessity

I've designed this by myself. In my case products cannot be in two or more categories. Each category is totally different.

17 minutes ago, kongondo said:

That may not be very foolproof (could children have been manually deleted?)

Children can be deleted manually. I've changed it to this:

 if (!$parent->hasChildren("template=$templatecat")) {
	//code
}

and $templatecat is the template the user choose for his/her categories. And I advice to keep this template always the same.

17 minutes ago, kongondo said:

Edit 2: Arrgh. Scrap that. That's not it really; Hopefully someone will chime in. You should be able to compare versions of your modules programmatically though; I'm sure of it

Thanks for the tip, will check this later today

 

(Maybe I just should forget this whole idea....)

Edited by Harmen
Edit
Link to comment
Share on other sites

Too early to give up maybe :). What is ranking in this case? What I meant specifically is are you sure $imgfield is an Image object? Is ranking an Image object or some other field on the page?

@note: I edited my post above about output formatting; don't know if you saw that.

Link to comment
Share on other sites

Once the module established a connection with the database the following screen shows up:

9a001c4d887be6e1888e3613fd3eb45f.png

So the ranking is to first import the categories, then products, followed by features and images. If you first click on products, but you've never done a import before the module will give you a message:ad3f4182f20c728126007d914d35a12e.png

and you will stay on the same page so you can first import your categories. 

The code for this 'ranking':

if (!$parent->hasChildren()) {
            if ($this->input->post->importcat) { //button categories
                $this->session->done = 1; //store in a session categories are imported
                return $this->processForm21($form);
            }

            //When button is clicked to import the products...
            if ($this->input->post->importprod) {
                if ($this->session->done >= 1) { //check if categories are imported
                    $this->session->done = 2;	//store in session you've imported the products
                    return $this->processForm31($form);

                } else $this->message(__("First import the categories"));
            }

            //When button is clicked to import the features...
            if ($this->input->post->importfeat) {
                if ($this->session->done >= 2) {	//check if products are imported
                    return $this->processForm41($form);
                } else $this->message(__("First import the products."));
            }

            //When button is clicked to import the images...
            if ($this->input->post->importimg) {
                if ($this->session->done >= 2) { //check if products are imported
                    return $this->processForm51($form);
                } else $this->message(__("First import the products."));
            }
        }

$imgfield refers to this field (which is now empty because I can't perform the import due to the error)

deb3e722bcad60b6cacd56bc369dc979.png

14 minutes ago, kongondo said:

@note: I edited my post above about output formatting; don't know if you saw that.

Yup, noticed it 

Link to comment
Share on other sites

So, my question still remains. Maybe confirm with some simple debugging of what this returns:

$imgfield = $product_pages->images_product;
echo gettype($imgfield);

Since you are getting the 'non-object' error, I'm pretty sure that will echo NULL.

Link to comment
Share on other sites

6 minutes ago, kongondo said:

 

So, my question still remains. Maybe confirm with some simple debugging of what this returns:

 

Sorry, here's what I got with your piece of code:

Quote

objectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectobjectNULLNULLNULLobjectobjectNULLNULLNULLNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectobjectobjectobjectNULLNULLNULLobjectNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectNULLNULLNULLobjectNULLobjectNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLNULLNULLobjectobjectobjectobjectobjectNULLobjectNULLNULLobjectobjectobjectNULLNULLNULLobjectNULLNULLNULLNULLNULLNULLobjectobjectNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectNULLNULLobjectNULLNULLNULLobjectNULLNULLNULLobjectobjectobjectNULLNULLobjectNULLobjectobjectobjectobjectobjectNULLobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectNULLobjectNULLobjectNULLNULLNULLNULLNULLNULLNULLNULLobjectNULLNULLobjectNULLNULLobjectobjectobjectobjectobjectobjectNULLNULLNULLobjectobjectNULLobjectobjectobjectNULLNULLNULLNULLNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectNULLNULLNULLNULLobjectNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectNULLNULLNULLobjectNULLobjectNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectobjectNULLobjectNULLNULLNULLobjectNULLobjectobjectobjectNULLNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectobjectobjectNULLobjectNULLobjectNULLobjectobjectNULLobjectobjectNULLobjectNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectNULLNULLobjectobjectNULLNULLNULLNULLNULLNULLNULLobjectNULLobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectNULLNULLNULLobjectobjectNULLNULLNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectobjectobjectNULLNULLNULLNULLobjectNULLNULLNULLNULLNULLobjectobjectNULLNULLNULLNULLNULLNULLobjectNULLobjectobjectobjectobjectobjectNULLobjectNULLobjectobjectNULLNULLNULLobjectNULLNULLNULLNULLobjectNULLNULLNULLNULLobjectNULLobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectobjectobjectNULLobjectobjectobjectobjectNULLobjectobjectNULLobjectNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectNULLNULLobjectNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectNULLobjectobjectNULLobjectNULLobjectobjectNULLNULLNULLNULLNULLNULLobjectobjectobjectobjectobjectobjectobjectobjectNULLNULLobjectobjectobjectNULLobjectNULLNULLobjectobjectobjectobjectNULLobjectobjectNULLNULLobjectNULLobjectNULLNULLNULLobjectobjectNULLobjectNULLNULLNULLobjectNULLNULLobjectobjectobjectNULLobjectNULLNULLNULLobjectNULLNULLNULLobjectobjectobjectNULLobjectNULLobjectNULLobjectobjectNULLobjectobjectNULLNULLNULLNULLNULLNULLNULLNULLobjectNULLNULLNULLNULLNULLobjectNULLobjectNULLNULL

This confuses me... I think it gives the types of all the $imgfields

Link to comment
Share on other sites

Allright, this is weird.

I checked my code again, uploaded it, installed tracydebugger to see if that gives me more info, and suddenly it works!

Tried it several times again and it really works.

I didn't make any changes in my code but it works for now. Now asking myself: what causes the error...

In any case, thanks for your help @kongondo!

f6996196a3759a623431167836a586d6.png

Link to comment
Share on other sites

Actually I suspected that but forgot to mention it. Since you are in a foreach loop, it means that this code does not always get a page, i.e. some of the pages don't exist. 

$product_pages = wire("pages")->get("productid=$id_product"); //get the correct page so the images are placed in the correct product page

Change that to:

 // get the correct page so the images are placed in the correct product page
$product_pages = $this->wire("pages")->get("productid=$id_product");
if(!$product_pages) continue;

I assume you've previously sanitised the values of $id_product. Are they integers or strings? What type of field is productid? 

Link to comment
Share on other sites

9 minutes ago, Harmen said:

I checked my code again, uploaded it, installed tracydebugger to see if that gives me more info, and suddenly it works!

Does the Errors panel on the Tracy Debugbar show any warnings/notices?

Because of the way Tracy intercepts notices/warnings, sometimes it can cause code to work that would have otherwise failed. As far as I can tell this only happens with AJAX events where the notice would break the script because of header issues or just polluting of a JSON response. The key thing though is that with recent versions of Tracy, the notice/warning will always appear in the Errors panel so you are notified that something needs fixing.

Link to comment
Share on other sites

I will implement the changes.

6 minutes ago, kongondo said:

I assume you've previously sanitised the values of $id_product. Are they integers or strings? What type of field is productid? 

 $id_product are integers for the products. I get these from the database. Each products has it own id, and I link the images to the product trought that id. productid is an integer field where I store the integer of that product. 

 

Link to comment
Share on other sites

7 minutes ago, kongondo said:

Seems you posted at the same time.

True :rolleyes: 

At that time Tracy Debugger didn't show any errors @adrian. To check if it really had nothing to do with your module I uninstalled it (will install it again, no worries ;) ) and tried to import the images again. Everything worked as expected again. 

It feels a bit unreal to me, as I tried many things and now it works on the code I wrote at the start of developing this feature.

  • Like 1
Link to comment
Share on other sites

4 minutes ago, Harmen said:

It feels a bit unreal to me, as I tried many things and now it works on the code I wrote at the start of developing this feature.

Cache....or staring at a screen for too long can do that to you sometimes :P.

  • Like 1
Link to comment
Share on other sites

12 hours ago, kongondo said:

You should be able to compare versions of your modules programmatically though; I'm sure of it.

I think kongondo might be referring to the upgrade() method. From the docs:

Quote

upgrade($fromVersion, $toVersion)

This method is called when a version change is detected. This method should make any adjustments needed to support the module from one version to another. The previous known version ($fromVersion) and new version ($toVersion) are provided as arguments.

So in your module upgrade method you can do something like:

// Upgrade from < v0.0.5
if($fromVersion < 5) {
    // do something
}

 

  • Like 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...