Stuck on making template for Express List Block - Showing images

Permalink
Hey Folks,

Since the Slack/IRC bridge seems to be broken, I'm going to post here, hopefully I can get some help.

I'm trying to create a template for the Express List Block, initially to override when Images are present. Currently the block just says the name of the file and hyperlinks to the image. What I want instead is to actually show the image instead.

I think I've found the relevant section of the view.php file, however I don't think I'm using the methods correctly here as my testing results in php error pages complaining about a method that doesn't exist (at least, how I'm using it).

Here is what I have so far, starting at line 98 in the original view.php:

foreach ($result->getItems() as $item) { ?>
                <tr class="<?=$rowClass?>">
                <?php foreach ($item->getColumns() as $column) {
                    if ($column->getAttributeTypeHandle() == 'image_file') { ?>
                        <td><img src="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>"></td>
                    <?php
                    } elseif ($controller->linkThisColumn($column)) { ?>
                        <td><a href="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>"><?=$column->getColumnValue($item);?></a></td>
                    <?php
                    } else { ?>
                        <td><?=$column->getColumnValue($item);?></td>
                    <?php
                    } ?>
                }
                <?php


I will want to revisit how the if/else's work, as they're not quite how I want right now. But I'm trying to figure out how to roughly get the image to show.

The error being thrown is "Call to undefined method Concrete\Core\Search\Result\ItemColumn::getAttributeType()"

Which makes sense as I dig into the API documentation, however I am not entirely sure how to achieve what I want at this point, as I don't know what I can do with "$key", which seems to be a value I can retrieve from the "ItemColumn" aspect (unsure which proper term to use here). I know other "aspects" seem to have the ability to tell if it's an image, but I'm not sure how to bridge that gap right now.

I also added this to the beginning, but it didn't help, unsure if actually needed at all (line 6):

use Concrete\Core\Entity\Attribute\Key\Key;


I've been piecing this together from other sources of info like forum posts, etc, no clear answer just yet. Any help would be appreciated! Thanks!

BloodyIron
 
BloodyIron replied on at Permalink Reply
BloodyIron
Yuck that paste of code block really came out messy, sorry about that.
mnakalay replied on at Permalink Reply
mnakalay
the snippet you posted doesn't contain any call to method getAttributeType() so the error might be coming from another place in the code.
BloodyIron replied on at Permalink Reply
BloodyIron
Sorry, the code in my repo vs in my test system isn't 100% sync'd just yet as I'm trying to suss this out. The line "101" that is throwing the error is:

if ($column->getAttributeType() == 'image_file') { ?>


So yeah, it is being used (just not accurately represented in the original post), and I'm not sure what I should change about how I'm accomplishing this. Namely, I want to tell if the "column" entry is an image file type or not, then act based on that.
mnakalay replied on at Permalink Reply
mnakalay
Not 100% sure but $column->getColumnKey() should give you something of the form ak_handle_of_your_attribute

So remove the ak_ and you'll get the attribute's handle.

From there grab the attribute and from it grab the type's handle
BloodyIron replied on at Permalink Reply
BloodyIron
I am not sure how to get the handle and the attribute type, those steps are unclear to me. I am new to this.

edit: to clarify, I'm not yet sure how to _derive_ the methods to meet the functions you just described. The API documentation really is not self-indicative.
JohntheFish replied on at Permalink Reply
JohntheFish
An alternate approach, use my Omni Gallery addon to list express objects and show the images from their attributes as a slider or gallery. It doesn't do live filtering, but if you just need to display the list of images (and some other attributes such as text), Omni Gallery is an easy way to do it.

https://www.concrete5.org/marketplace/addons/omni-gallery/...
BloodyIron replied on at Permalink Reply
BloodyIron
I need to present the information that the Express List Block shows, this is not the job of an image gallery as other info is desired here too. Namely a lot of the attributes of Express Entries.
JohntheFish replied on at Permalink Reply
JohntheFish
As long as the express object has an image to start with, Omni Gallery can show attributes of the express object with the image.

As an extreme example, it can pretend to list the express objects as pages using a page list template, where the page list template thinks it is listing pages, but is actually listing the express object and its attributes.
BloodyIron replied on at Permalink Reply
BloodyIron
It's going to be lists of things that have different images associated with each. I want them all to be displayed at once (until a certain number happens) then it moves into pagification. The gallery addon you propose does not look suitable for that.

Furthermore, I need to better understand how to do templates as there's a lot of other blocks I need to write them for and I need a better understanding to do that.
JohntheFish replied on at Permalink Reply
JohntheFish
I quite understand that you want to learn about doing such for yourself, and as such, an off-the-shelf or near off-the-shelf solution isn't what you are looking for.

(it can handle pagination)
mnakalay replied on at Permalink Reply
mnakalay
To get the attribute type handle do this
$columnKey = $column->getColumnKey(); // ak_some_attribute_handle
$attrHandle = substr($columnKey, 3); // remove the ak_ to get the attribute's handle
$category = $entity->getAttributeKeyCategory(); // get the attribute category (here it's Express)
$attribute = $category->getAttributeKeyByHandle($attrHandle); // get the attribute object now that we have its handle and its category
// some columns are not for attributes but for other objects like associations or default fields so make sure you do have an attribute before getting its type
if ($attribute && is_object($attribute)) {
    $attrTypeHandle = $attribute->getAttributeTypeHandle();
    // do your stuff with $attrTypeHandle
}


The line where you're getting the category should probably be outside the loop that runs through all the columns since it never changes. I let you do that properly.

I hope this helps
BloodyIron replied on at Permalink Reply
BloodyIron
After wrestling with curly braces and scopes for a while (doing it wrong, clearly) I was able to get it to not throw errors, However the Express List Block is now detecting the date type as an image type, and replacing the date with an img type link, lol, not what I was anticipating. Unsure what I'm doing wrong here: (lines 97 through 121)

<tr class="<?=$rowClass?>">
                <?php foreach ($item->getColumns() as $column) {
                    $columnKey = $column->getColumnKey(); // ak_some_attribute_handle
                    $attrHandle = substr($columnKey, 3); // remove the ak_ to get the attribute's handle
                    $category = $entity->getAttributeKeyCategory(); // get the attribute category (here it's Express)
                    $attribute = $category->getAttributeKeyByHandle($attrHandle); // get the attribute object now that we have its handle and its category
                    // some columns are not for attributes but for other objects like associations or default fields so make sure you do have an attribute before getting its type
                    if ($attribute && is_object($attribute)) { 
                        $attrTypeHandle = $attribute->getAttributeTypeHandle();
                        // do your stuff with $attrTypeHandle
                    if ($attrTypeHandle == 'image_file') { ?>
                        <td><img src="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>"></td>
                    <?php
                    } elseif ($controller->linkThisColumn($column)) { ?>
                        <td><a href="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>"><?=$column->getColumnValue($item);?></a></td>
mnakalay replied on at Permalink Reply
mnakalay
remove the code you added to spit out the image, all the code, and instead write
echo $attrHandle . ' ' . $attrTypeHandle . '<br>';

And see what happens
BloodyIron replied on at Permalink Reply
BloodyIron
Instead of removing the code, I added your line...

$columnKey = $column->getColumnKey(); // ak_some_attribute_handle
                    $attrHandle = substr($columnKey, 3); // remove the ak_ to get the attribute's handle
                    echo $attrHandle . ' ' . $attrTypeHandle . '<br>';
                    $category = $entity->getAttributeKeyCategory(); // get the attribute category (here it's Express)
                    $attribute = $category->getAttributeKeyByHandle($attrHandle); // get the attribute object now that we have its handle and its category


This was the output just above the block it seems:

xEntryDateCreated
xEntryDateModified
game_name
game_thumbnail text
ociation_111e5cde-26bd-11eb-8d56-2221c0b44dd4 image_file
ociation_8da745cb-3fc4-11eb-8d56-2221c0b44dd4 image_file
ociation_b950c478-26c3-11eb-8d56-2221c0b44dd4 image_file


The "Date Modified" column is where it tries to put an img tag, and then every other column visually appears "blank", suggesting to me the iteration breaks after it encounters something that triggers the img replacement once. Unsure if that's correct or not.
mnakalay replied on at Permalink Reply
mnakalay
Where you put it it's not goint to work since we don't have the attribute type handle yet. Put it right after
$attrTypeHandle = $attribute->getAttributeTypeHandle();
BloodyIron replied on at Permalink Reply
BloodyIron
This is what I get when I move it as you describe: (not sure why it's only doing 2x iterations here... the block has 7x columns "active")

game_name text
game_thumbnail image_file


And specifics of where I put it....

<?php foreach ($item->getColumns() as $column) {
                    $columnKey = $column->getColumnKey(); // ak_some_attribute_handle
                    $attrHandle = substr($columnKey, 3); // remove the ak_ to get the attribute's handle
                    $category = $entity->getAttributeKeyCategory(); // get the attribute category (here it's Express)
                    $attribute = $category->getAttributeKeyByHandle($attrHandle); // get the attribute object now that we have its handle and its category
                    // some columns are not for attributes but for other objects like associations or default fields so make sure you do have an attribute before getting its type
                    if ($attribute && is_object($attribute)) { 
                        $attrTypeHandle = $attribute->getAttributeTypeHandle();
                        // do your stuff with $attrTypeHandle
                        // BELOW IS TESTING LINE
                        echo $attrHandle . ' ' . $attrTypeHandle . '<br>'; //TESTING LINE FOR MNAKALAY
                        // ABOVE IS TESTING LINE
                    if ($attrTypeHandle == 'image_file') { ?>
                        <td><img src="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>"></td>
                    <?php
mnakalay replied on at Permalink Reply
mnakalay
that's normal. Out of your 7 fields only these 2 are attributes. The first 2 are default values (date created and date modified) and the others are all associations.

Only attributes have an attribute type. You said you needed to know which attribute had an image. That's the second one with the attribute type of image_file.

So what we can say is that at least that aspect of the code works correctly

Now you don't see anything because you are outputting an image <img> but instead of the URL to an image you are using the URL to a page

<img src="<?=URL::to($detailPage, 'view_express_entity', $item->getEntry()->getId())?>">


So correct the line above like this and see if it works
<img src="<?=$attribute->getPlainTextValue()?>">
BloodyIron replied on at Permalink Reply
BloodyIron
That resulted in PHP error

Call to undefined method Concrete\Core\Entity\Attribute\Key\ExpressKey::getPlainTextValue()
mnakalay replied on at Permalink Reply
mnakalay
ok. Try this instead
<img src="<?=$attribute->getController()->getPlainTextValue()?>">
BloodyIron replied on at Permalink Reply
BloodyIron
That produces:

Call to a member function getValue() on null


for "...concrete/attributes/image_file/controller.php"

line 85

$f = $this->getAttributeValue()->getValue();
mnakalay replied on at Permalink Reply
mnakalay
oh yes... Stupid mistake, sorry. I'll get you the correct one in a bit.
mnakalay replied on at Permalink Reply
mnakalay
This should work

<?php 
$entry = $item->getEntry();
foreach ($item->getColumns() as $column) {
    $columnKey = $column->getColumnKey(); // ak_some_attribute_handle
    $attrHandle = substr($columnKey, 3); // remove the ak_ to get the attribute's handle
    $category = $entity->getAttributeKeyCategory(); // get the attribute category (here it's Express)
    $attribute = $category->getAttributeKeyByHandle($attrHandle); // get the attribute object now that we have its handle and its category
    // some columns are not for attributes but for other objects like associations or default fields so make sure you do have an attribute before getting its type
    if ($attribute && is_object($attribute)) { 
        $attrTypeHandle = $attribute->getAttributeTypeHandle();
        if ($attrTypeHandle == 'image_file') {
            $fv = $entry->getAttribute($attribute);
            if (is_object($fv)) {
                ?>
                <td><img src="<?=$fv->getURL())?>"></td>

Make sure you replace the whole foreach loop in your code from opening bracket to closing bracket.
stewblack23 replied on at Permalink Reply
stewblack23
Thanks for all this work everyone. I know I'm going to need to this for a up coming project.