Jump to content

Get image in the context of a hook


Recommended Posts

Hi,

depending on the status of a set checkbox (set_create_vcard) i generate VCF files on page save (admin). For this i have a hook (s. below) placed in admin.php. Everything behaves like it should. But when i try to integrate a image in the vcard i get the following message/error on page save (Returned data is not a image comes from the exception class of the VCard lib).

ProcessPageEdit: Returned data is not an image.

I am asking this question here in the PW Forum (and not on the github board of the lib), because integrating the (essentially) similiar code in a regular template file (e.g. outside the hook) works flawlessly (with the same images accepted, e.g do not trigger any error). I am rather a newbie when it comes to hooks. So its likely that i miss something.

Any hints much appreciated,
Olaf

<?php

// file: admin.php

// get vcard lib (composer module) on top
use JeroenDesloovere\VCard\VCard;

/**
 * Admin template just loads the admin application controller, 
 * and admin is just an application built on top of ProcessWire. 
 *
 * This demonstrates how you can use ProcessWire as a front-end 
 * to another application. 
 *
 * Feel free to hook admin-specific functionality from this file, 
 * but remember to leave the require() statement below at the end.
 * 
 */

$wire->addHookBefore('Pages::saveReady', function($event){
  $page = $event->arguments(0);
  if($page->hasField("set_create_vcard")) {
    if($page->set_create_vcard == 1) {
      $page->set_create_vcard = 0;

      // define vcard
      $vcard = new VCard();

      // define variables
      $fullname = $page->combo_contact->name;

      // add personal data
      $vcard->addName($fullname);

      /* ... some other allocations ... */

      // WHERE IT BREAKS...
      if($page->image_contact) {
        $vcard->addPhoto($page->image_contact->filename);
      }

      $vcard->setSavePath($this->wire('config')->paths->root.'process/public/vcard');
      $vcard->save();

      $this->message('VCF Datei für den Kontakt wurde erstellt');

    }
  }
});

// Do not touch...
require($config->paths->adminTemplates . 'controller.php');

 

  • Like 1
Link to comment
Share on other sites

I believe you are using a single images field, means the allowed amount of stored image is set to 1.

If that is true, the scope where you calling it is important. Behind the scenes a single image field and a multiple images field are the same, they only behave different in template scope, where output formatting is set to true by default. For single image fields this reduces the code a bit so that you already act with a single image right after the field name.

So in a function or method scope, this is not (cannot be) auto set to true, and your image field returns a collection from which you have to select the first item: 

$page->image_contact->first()

So a working code then can be: 

      if(0 < count($page->image_contact)) {
        $vcard->addPhoto($page->image_contact->first()->filename);
      }

 

  • Like 3
Link to comment
Share on other sites

And if you want to make things a little more obvious to anybody reading your code (or simply to yourself) you can use getUnformatted() to return the array version of the field no matter what the current outputformatting is:

<?php
$images = $page->getUnformatted('imagesfield');
if($images->count()) {
  $img = $images->first();
  ...
}

 

  • Like 2
Link to comment
Share on other sites

6 minutes ago, bernhard said:

getUnformatted()

Ha, that's what I use only and everywhere since a couple of years already. Because the code then is bulletproof, even if sometimes in the future a single image field need to be changed to a multiple one or vise versa. No changes in code are needed.
First I thought to mention that too, but decided that it may be not close enough to the topic. So good that you brought it up! 🙂

  • Like 1
Link to comment
Share on other sites

1 hour ago, bernhard said:

And if you want to make things a little more obvious to anybody reading your code (or simply to yourself) you can use getUnformatted() to return the array version of the field no matter what the current outputformatting is

True, but just want to point out there can be occasional "gotchas" when doing this because PW sometimes returns things that may be unexpected in the unformatted value.

For example, the unformatted value of a Page Reference field will include unpublished pages and the unformatted value of a Repeater field can include "ready" items that are not populated in Page Edit.

And in the case being discussed here the unformatted value of an images field can include "temporary" images that have been uploaded in Page Edit but the page has not yet been saved. So in the example below the frog image is saved but the fish image has just been uploaded but not yet saved, and might yet be abandoned before saving because of being a mistake or unwanted. Yet it appears in the unformatted value:

2022-04-02_135142.png.61478c53545db48fac41da1afbae9ddf.png

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, Robin S said:

And in the case being discussed here the unformatted value of an images field can include "temporary" images that have been uploaded in Page Edit but the page has not yet been saved. So in the example below the frog image is saved but the fish image has just been uploaded but not yet saved, and might yet be abandoned before saving because of being a mistake or unwanted. Yet it appears in the unformatted value:

Very interesting details, that I haven't known. So my use cases for getUnformatted("imagesField") is in template / frontend context only. I haven't had a need to use this in the admin, but definitely will note that down for when this use case may arise.

Link to comment
Share on other sites

6 minutes ago, horst said:

I haven't had a need to use this in the admin, but definitely will note that down for when this use case may arise.

It's not different between frontend and admin - I just used that in my screenshot to show the as-yet-unsaved image. So you do have to watch out for it in template code too. Suppose you have a busy site and you're using getUnformatted() in your template code. If a website editor accidentally uploads the wrong image (you can imagine some worst-case scenarios here!) but then notices before they save the page, that temporary image might have already been displayed and viewed on the frontend via getUnformatted().

  • Like 3
Link to comment
Share on other sites

Ok, I see. But I also every time use ProCache(d) sites and the authors do know that they can edit a page without changes on the front end as long as they do not save it. But I see, it isn't that "bullet-proof" I thought it is, (in the front end too). Thanks for pointing that out!

  • Like 1
Link to comment
Share on other sites

10 hours ago, horst said:

I believe you are using a single images field, means the allowed amount of stored image is set to 1.

If that is true, the scope where you calling it is important. [...]

@horst Your assumptions were all right. Argh, it happened quite more than once that i simply forgot about that. Thank you very much for your brief and clear explanation.

@bernhard @Robin S Big thanks also for your advice and details.

  • Like 3
Link to comment
Share on other sites

Thx @Robin S I definitely didn't have that on my radar!

Do you have a suggestion what to use if I just want to make sure to get the images' field data as array independently from the template context but not showing temporary or unpublished items?

Link to comment
Share on other sites

@bernhard At first glance this can work, but I need to do some thorough tests against different cases/situations/states a page and images can have.
It's just the first shot that came to my mind:

$page->getUnformatted('images')->find("created<{$page->modified}")

 

  • Like 1
Link to comment
Share on other sites

11 hours ago, bernhard said:

Do you have a suggestion what to use if I just want to make sure to get the images' field data as array independently from the template context but not showing temporary or unpublished items?

I think a couple of ways are possible. One is similar to what @horst suggested, but you can use the special created timestamp of 10 to more exactly identify temporary images:

$page->getUnformatted('images')->find('created!=10')

There are also the public Pagefile::isTemp() and Pagefiles::isTemp() methods that can be used to check if a particular Pagefile/Pageimage is temporary or not.

Another way would be to set the outputFormat property of the images field to array before you get the field value so that the value is standardised for single and multiple image fields.

$page->getField('image')->outputFormat = FieldtypeFile::outputFormatArray;
// Now use $page->image

 

  • 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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...