I've spent most of the day trying to wrap my head around multidimensional arrays, in order to build a PHP function that I can call to populate an image gallery that could potentially hold 100s of elements. At this point it would have been easier to just copy and paste the HTML portion over and over again, but I'd like to figure out how to make this work, for future projects.
I have found solutions to other questions about foreach loops with multidimensinoal arrays, but I haven't been able to adapt them to my case. In one instance, the closest to my own situation, the solution no longer works--but I don't have the rep to make a comment about it. I used the code from that example as the basis for my own attempt. I welcome any assistance! My comments may help explain what I'm trying to achieve, if it isn't already clear.
Here is my PHP code so far:
<?php
// Use PHP array to populate the image path, title (for alt tag), and longer description (for image caption)
function build_html ($imgsrc, $title, $desc) {
echo
'<div class="responsive">
<div class="gallery">
<img src="$imgsrc" alt="$title" width="300" height="200">
<div class="desc">$desc</div>
</div>
</div>';
}
// List of images; filenames will be numerical, so later I may switch to using $i++ shortcut in place of imgsrc
$gallery = array (
array (
"imgsrc" => "i/Alice0.jpg",
"title" => "Front of House",
"desc" => "View of the house from the front sidewalk"
),
array (
"imgsrc" => "i/Alice1.jpg",
"title" => "Front door",
"desc" => "Close-up of front door"
)
);
// This is just for debugging, to confirm that I really have a multidimensional array
print_r($gallery);
// BROKEN: this should use foreach loop(s) to gather the elements and pass them to the build_html function defined above.
function display_gallery () {
foreach ($gallery as $img) {
$imgsrc = $img['imgsrc'];
$title = $img['title'];
$desc = $img['desc'];
build_html($imgsrc, $title, $desc);
}
}
// Calling the function in body of page
display_gallery();
?>
Edit: The error message I'm currently getting is:
Warning: Invalid argument supplied for foreach() in
/home/varlokkur/house.anthropo.org/index.php on line 121
Edit: In case anyone stumbles across this question in the future, here is my modified code that works as expected. Note that the solution offered by aendeerei is a better example to follow, but this solution is closest to the original code. 2 changes to make it work:
Fixed built_html function to properly use the variables that are passed
Fixed display_gallery function to use the $gallery variable
Fixed code:
<?php
// Use PHP array to populate the image path, title (for alt tag), and longer description (for image caption)
function build_html ($imgsrc, $title, $desc) {
echo
'
<div class="responsive">
<div class="gallery">
<img src="' . $imgsrc . '" alt="' . $title . '" width="300" height="200">
<div class="desc">'. $desc . '</div>
</div>
</div>
';
}
// List of images; filenames will be numerical, so later I may switch to using $i++ shortcut in place of imgsrc
$gallery = array (
array (
"imgsrc" => "i/Alice0.JPG",
"title" => "Front of House",
"desc" => "View of the house from the front sidewalk"
),
array (
"imgsrc" => "i/Alice1.JPG",
"title" => "Front door",
"desc" => "Close-up of front door"
)
);
// This is just for debugging, to confirm that I really have a multidimensional array
//print_r($gallery);
// BROKEN: this should use foreach loop(s) to gather the elements and pass them to the build_html function defined above.
function display_gallery ($gallery) {
// global $gallery;
foreach ($gallery as $img) {
$imgsrc = $img['imgsrc'];
$title = $img['title'];
$desc = $img['desc'];
build_html($imgsrc, $title, $desc);
// var_dump($gallery);
}
}
//var_dump($gallery);
// Calling the function in body of page
display_gallery($gallery);
?>
Unlike in JavaScript, there is no scope bubbling in PHP. A function scope in PHP is isolated from the outside scope. Your $gallery is defined outside the function scope. Inside the function, it is undefined. That is why you get the Invalid argument supplied for foreach() message, because foreach expects an array, but it's not there. When you var_dump($gallery) in the function, you will see it is undefined.
The solution is to pass $gallery to display_gallery(), e.g.
function display_gallery(array $gallery) {
// the code as is
}
display_gallery($gallery);
An alternative would be to utilize the global keyword:
function display_gallery() {
global $gallery;
// the code as is
}
display_gallery();
However, while the latter looks like a convenient and simple fix, reaching from an inner scope to an outer scope is usually harder to maintain and more error prone in the long run. I am including it for the sake of completeness, but would advice to use the first approach, e.g. passing in the variable.
Notes:
I've separated the file name in images list, so it can also be used properly if it's maybe going to become an integer in the future.
I added additional infos, like "alt", "width", "height". "Alt" means
alternative text, showed when image can not be displayed. But "title"
is the attribute used for the tooltips on hover.
I changed the function names to intention-revealing names. And I wanted to show you that the function/method names in PHP should be defined in "camelCase" format (see PHP recommendation PSR-1: Basic Coding Standard).
I used the function sprintf() in displayImageCard(), to show you how to achieve a better readability and separation of PHP variables from the output string.
You should "inject" the $gallery array as argument to the displayImageGallery() function. The lack of this function argument was the source of the error you received.
Good luck!
<?php
/*
* -----------------
* Gallery functions
* -----------------
*/
/**
* Display image card.
*
* #param string $file File name.
* #param string $extension File extension (jpg|png, etc).
* #param string $path File path.
* #param string $alt Alternative text.
* #param string $title Title used in tooltips.
* #param string $description Description.
* #param integer $width Width.
* #param integer $height Height.
* #return string Output string.
*/
function displayImageCard($file, $extension, $path, $alt, $title, $description, $width = 300, $height = 200) {
echo sprintf('<div class="responsive">
<div class="gallery">
<img src="%s" alt="%s" title="%s" width="%s" height="%s">
<div class="desc">%s</div>
</div>
</div>'
, $path . $file . '.' . $extension
, $alt
, $title
, $width
, $height
, $description
);
}
/**
* Display image gallery.
*
* #param array $gallery [optional] Images list.
* #return void
*/
function displayImageGallery(array $gallery = array()) {
echo '<pre>' . print_r($gallery, true) . '</pre>';
foreach ($gallery as $key => $image) {
$file = $image['file'];
$extension = $image['extension'];
$path = $image['path'];
$alt = $image['alt'];
$title = $image['title'];
$description = $image['description'];
displayImageCard($file, $extension, $path, $alt, $title, $description);
}
}
/*
* ---------------
* Display gallery
* ---------------
*/
// Images list.
$gallery = array(
array(
'file' => 'i/Alice0',
'extension' => 'jpg',
'path' => 'abc/',
'alt' => 'Front of House',
'title' => 'Front of House',
'description' => 'View of the house from the front sidewalk',
),
array(
'file' => 'i/Alice1',
'extension' => 'jpg',
'path' => 'def/',
'alt' => 'Front door',
'title' => 'Front door',
'description' => 'Close-up of front door',
)
);
// Display image gallery.
displayImageGallery($gallery);
This will solve it:
function display_gallery ($gallery) {
foreach ($gallery as $img) {
$imgsrc = $img['imgsrc'];
$title = $img['title'];
$desc = $img['desc'];
build_html($imgsrc, $title, $desc);
}
}
// Calling the function in body of page
display_gallery($gallery);
As well you could put the part where you define your array in function:
function returnArray() {
// $gallery = ...
return ($gallery);
}
And then in foreach loop:
foreach (returnArray() as $img) { ... }
To organize better my code, I would like to split some of my HTML in templates.
I have a loop inside a shortcode to get the posts:
function nh_shortcode_func($atts) {
$posts = get_posts_by_category(.......);
$html .= '';
foreach ($posts as $post) {
$post_id = $post->ID;
$post_title = $post->post_title;
$post_image = get_field('image', $post_id);
$html .= **HERE THE CODE OF HTML WITH DIVS AND CLASSES**
}
return $html
}
add_shortcode('nh-content', 'nh_shortcode_func');
Instead, put my HTML code inside a variable, I would like to use another file with the HTML structure that I'm going to use to build the posts. Also, I would like to pass the dynamic data to it.
Any ideas?
Thanks.
Just use an include file and it will have access to the variables. Something like:
function nh_shortcode_func($atts) {
ob_start();
include dirname( __FILE__ ) . '/templates/nh_shortcode.php';
return ob_get_clean();
}
add_shortcode('nh-content', 'nh_shortcode_func');
I have a search submit button, and I want my application to open another view on click. This is my code:
views/supermarkets/index.php:
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
use app\views\supermarkets\search;
?>
<h1>Supermarkets</h1>
<ul>
<p>
Search by Name
</p>
<Form Name ="form1" Method ="POST" ACTION = "app\views\supermarkets\search.php">
<INPUT TYPE = "Text" VALUE ="search by name" NAME = "searchname">
<input type="submit" value="Search">
<h3> </h3>
views/supermarkets/search.php:
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Supermarkets</h1>
<ul>
<?php
if (isset($_POST['searchname']) && $_POST['searchname']!='') {
$sname = $_POST['searchname'];
$row = Yii::app()->db->createCommand(array(
'select' => '*',
'from' => 'supermarkets',
'where' => array('like', 'Name','%'.$keyword.'')
))->queryRow();
$array = (array) $row;
}
echo $array;
function build_table($array){
// start table
$html = '<table class="altrowstable" id="alternatecolor">';
// header row
$html .= '<tr>';
foreach($array[0] as $key=>$value){
$html .= '<th>' . $key . '</th>';
}
$html .= '</tr>';
// data rows
foreach( $array as $key=>$value){
$html .= '<tr>';
foreach($value as $key2=>$value2){
$html .= '<td>' . $value2 . '</td>';
}
$html .= '</tr>';
}
// finish table and return it
$html .= '</table>';
return $html;
}
echo build_table($array);
?>
<?= LinkPager::widget(['pagination' => $pagination]) ?>
On Submit I'm getting this error:
Object not found!
The requested URL was not found on this server. The link on the referring page seems to be wrong or outdated. Please inform the author of that page about the error.
If you think this is a server error, please contact the webmaster.
I know there is something wrong in my code, but I just can't figure it out. And I am not sure if this is the right way to submit the POST value to my search view.
Your issue arises from this line :
<Form Name ="form1" Method ="POST" ACTION = "app\views\supermarkets\search.php">
The action must be a callable URL. Instead, you are providing a path to the view file.
Using the Yii MVC convention, you will need to generate a controller function and point the form action to that path.
In your view :
< form name ="form1" method ="POST" action="<?php Yii::createUrl('supermarket/search'); ?>" >
In your controller:
class SupermarketController extends CController
{
public function actionSearch()
{
// ... Your code here.
$this->render('another_view', array(...);
}
}
You should not use absolute path in your project. Here the list of methods I used in Yii1. Hope it will works in Yii2.
Create URL
$url = Yii::app()->createUrl('site/index', array('id'=>100));
Create URL from Controller
Yii::app()->controller->createUrl("index", array("id"=>100));
Create absolute URL
Yii::app()->createAbsoluteUrl('site/index',array('id'=>100));
Create Link
echo CHtml::link('text', array('site/index', 'id'=>100));
Redirect Browser
$this->redirect(array('site/index','id'=>100));
Remove array('id'=>100) for without values
View files inside the "protected" folder are not accessible directly by user.
crafter's answer is correct.
see here for information about controller
Im creating a custom function for my wordpress website that will add a review section below the post content and i need to insert this function from another another file into a custom function that i added to my functions.php. I need to get this piece of code $buffy .= $this->get_review(); from a different file to work in this function:
function content_injector($content) {
global $wp_query;
$postid = $wp_query->post->ID;
if (is_single((get_post_meta($postid, 'top_ad', true) != 'off' ))) {
$top_ad = do_shortcode('[td_ad_box spot_name="Ad spot -- topad"]');
}
if (is_single((get_post_meta($postid, 'bottom_ad', true) != 'off' ))) {
$bottom_ad = do_shortcode('[td_ad_box spot_name="Ad spot -- topad"]');
}
if (is_single()) {
$review = //HOW DO I ADD THAT get_review CODE HERE?
$custom_share = '<div id="title-deel"><h4 class="block-title"><span>DEEL</span></h4></div>' . do_shortcode('[ssba]');
$facebook_comments = '<div id="title-reageer"><h4 class="block-title"><span>REAGEER</span></h4></div>' . '<div class="fb-comments" data-href="' . get_permalink() . '" data-colorscheme="light" data-numposts="5" data-mobile="false" data-width="700"></div>';
}
$content = $top_ad . $content . $bottom_ad . $custom_share . $facebook_comments;
return $content;
}
add_filter('the_content', 'content_injector');
As you can see i need to add the get_review function to $review, but i cant make it work on my own. How to make this work?
Use include to include the file before using any methods from that file.
include("file_with_functions.php");
OR
Create a class (with filename same as classname).
Include the file.
Create an instance of the class.
Access the method in the class through the object
I want to have some picture displayed when I click on some links but I don't know how to send them from the controller because everytime I have as src= {{ asset('bundles/fds/...') }}.How can I solve it?
public function getPictureAction() {
$html = '<div id="comment_list_div">';
$html .= '<div id="comment_list_div_img">';
$html .= '<div id="comment_list_div_im">';
$html .= '<img src="{{ asset('bundles/fds/images/Picture.png') }}"/>';
$html .= '</div>';
$html .= '</div>';
$html .= '</div>';
$return = array( "html" => $html);
$return = json_encode($return);
return new Response($return, 200, array('Content-Type'=>'application/json'));
}
The correct way to do this would be to move your html code into a template and render it in your action:
In your controller:
use Symfony\Component\HttpFoundation\JsonResponse;
// ...
public function getPictureAction() {
// load your picture from the db
$content = $this->renderView(
'AcmeHelloBundle:Json:JsonResponse.html.twig',
// pass the picture to your template:
array('imagePath' => $image->getPath())
);
return new JsonResponse(
$content,
200,
array('Content-Type'=>'application/json')
);
}
And your template:
<div id="comment_list_div">
<div id="comment_list_div_img">
<div id="comment_list_div_im">
{# use the vairable name you passed to this template to acces your image #}
<img src="{{ asset(imagePath) }}"/>
</div>
</div>
</div>
Also make sure your assets are in place:
php app/console assets:install
php app/console assetic:dump --env=dev