I am trying to make a own class in CodeIgniter and therefore I have made a file in the folder
libraries
This class is called
Menu
And it contains a class to create a navigation bar for my website. this class is like
class Menu {
public function draw($menu) {
$CI =& get_instance();
$output = '';
foreach ($menu as $key => $value) {
$output .= "<li>";
if (is_array($value)) {
if (strpos($key, '|') !== false) {
$param = explode('|', $key);
$output .= anchor($param[1], $param[0]);
} else {
$output .= anchor('#', $key);
}
$output .= PHP_EOL."<ul>".PHP_EOL;
$output .= draw($value);
$output .= "</ul>".PHP_EOL."</li>".PHP_EOL;
} else {
$output .= anchor($key, $value, $CI->uri->slash_segment(1, 'leading') == $key ? 'class="active"' : '');
$output .= "</li>".PHP_EOL;
}
}
return $output;
}
}
I have put this class in my config file as autoload under libraries
$autoload['libraries'] = array('menu');
When I call the class to use it I do this
<?php
$m = new Menu();
echo $m->draw($menu);
?>
But unfortunately I get this error
Fatal error: Call to undefined function draw() in /Users/username/Sites/infinity2.0/application/libraries/Menu.php on line 22
Line 22 is $output .= draw($value);
But I don't know how to solve this I think its because of calling its own method again.. any help is welcome and appreciated. :)
Change
$output .= draw($value);
to
$output .= $this->draw($value);
$this refers to the current object, so if you want to recursively call draw() within itself, you need to use it to refer to it..
You might want to read the explanation from the php.net website: http://php.net/manual/en/language.oop5.basic.php
Related
I'm trying to show a object in a html modal. Since I don't know the structure beforehand, and the child properties can also be objects or arrays, a simple recursive function seemed to be the way to go, but Im not sure. I have this:
<?php
class LogHelper extends Helper
{
public function warningLogError($body_error)
{
$data = [];
$html = '';
$html .= "<div name='bodyErrosr' class = 'form-group'>";
$html .= "<div class = 'alert alert-warning' role = 'alert'>";
if (!empty($body_error)) {
foreach($body_error as $key => $value) {
$html .= "<li><b>" . $key . "= " . $value. "</b></li>";
}
} else {
$html .= "<li><b>" . 'Error!' . "</b></li>";
}
$html .= "</ul>";
$html .= "</div>";
$html .= "</div>";
return $html;
}
}
But I don't know the structure beforehand, sometimes I receive an object inside object multiple times. How is the best way to do this?
Have a look at: https://packagist.org/packages/symfony/var-dumper
This also handles circular references (where print_r/vardump fail)
I have a problem with my code and can't find the error. This code works with PHP 7.0 but not with PHP 5.6. I need it to work in PHP 5.6. The error :Catchable fatal error: Argument 1 passed to XmlParser::__construct() must be an instance of string, string given.
class XmlParser
{
private $xml;
public function __construct($document)
{
$this->xml = simplexml_load_file($document);
}
public function xmlParserPICtn()
{
global $obj;
$valuesPICtn = $this->xml->xpath("//OBJEKT[#ID='$obj']//BILD");
foreach ($valuesPICtn as $PICelements) {
$searchpattern = '#https://([^"]+)#';
preg_match($searchpattern, $PICelements->PIC, $valuesPICt); //Search-String
$display .= '<li data-thumb=https://';
$display .= $valuesPICt[1];
$display .= '>';
$display .= '<img src=https://';
$display .= $valuesPICt[1];
$display .= '></li>';
}
return $display;
}
}
I'm in the process of learning php so forgive me if this is a silly question. I'm trying to make a dynamic gallery that looks through a folder(./JIN/snoii/) and produces the html code for the number of items in said folder. This code I've written isnt returning anything when the file has images(currently has over a hundred) can some one tell me where I messed up or point me in the right direction. Thanks in advance
$CurrentViewFile = "snoii";
function showGallery(){
global $CurrentViewFile;
$galleryHTML = "<h1>Dynamic gallery</h1>";
$galleryHTML .= "<ul>";
$folderToview = "JIN/";
$folderToview .= $CurrentViewFile;
$images = new DirectoryIterator($folderToview);
while($images->valid()){
$galleryHTML .= "<li>!!</li>";
$images->next();
}
$galleryHTML .= "</ul>";
return $galleryHTML;
}
return showGallery();
Your DirectoryIterator makes the problem,
Please try like this
$CurrentViewFile = "/snoii";
function showGallery(){
global $CurrentViewFile;
$galleryHTML = "<h1>Dynamic gallery</h1>";
$galleryHTML .= "<ul>";
$folderToview = "JIN/";
$CurrentViewFile .= $folderToview;
foreach (new DirectoryIterator($CurrentViewFile) as $images) {
if($images->valid())
$galleryHTML .= "<li>!!</li>";
$images->next();
}
$galleryHTML .= "</ul>";
return $galleryHTML;
}
$output_data = showGallery();
echo $output_data;
If you want to get file name from the iterator you should use like this,
$images->getFilename()
I created this array with a circular reference:
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
I have a function that recursively prints out the values in an array, but I really couldn't solve the problem of creating a circular reference check. How can you do that?
The current function I have for printing the array is copied below. I haven't included the various attempts I made at doing the circular reference check. They mainly revolved around a strategy of maintaining a $seen array of items that have already been printed for each branch of recursion. This is because I still want to allow the printing of duplicate values, just not printing of a value if it is a parent of the current array being parsed.
The problems I had were figuring out how to add references rather than array copies to this $seen variable. But I'd be happy to use another strategy all together if it worked.
function HTMLStringify($arr)
{
if(is_array($arr)){
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if(is_array($value)){
//Conspicuously missing is a circular reference check,
//causing infinite recursion. After a few failed attempts
//at checking for this (e.g. discovering that array_push doesn't take references)
//I have left it for further study.
//(After all, Javascript's JSON.stringify() doesn't check for circular references)
//TODO: Check for circular references
$html .= HTMLStringify($value, $seen);
}
elseif(is_numeric($value) || is_string($value) || is_null($value))
{
$html .= ' = ' . $value;
}
else
{
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
else
{
return null;
}
}
An adapted version of your code, using the strict in_array check from the answer linked by Ryan Vincent, is shown below:
function HTMLStringify($arr, array $seen = array()) {
if (is_array($arr)) {
$seen[] = $arr;
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if (is_array($value)) {
if (in_array($value, $seen, true)) {
// Deal with recursion in your own way here
$html .= ' [RECURSION]';
} else {
$html .= HTMLStringify($value, $seen);
}
} elseif (is_numeric($value) || is_string($value) || is_null($value)) {
$html .= ' = ' . $value;
} else {
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
return $html . '</ul>';
} else {
return null;
}
}
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
echo HTMLStringify($arr);
Comparing across a number of PHP versions, it looks like this will work for PHP 5.3.15+ and PHP 5.4.5+.
i'm using this function for debugging. Also upgraded to detect recursive link.
function print_table($mixed, $level=9, $_callstack=array()){
if($level<=0){ echo '**LIMIT**'; return; }
if( array_search(serialize($mixed), $_callstack)!==false){
echo '***recursive detected***';
return ;
}
$_callstack[] = serialize($mixed);
if(is_array($mixed)){
echo '<table cellspacing="0" width="100%" border="1">';
foreach($mixed as $key=>$val){
echo '<tr><td width="20%">'.$key.'</td><td>';
if(is_array($val)){
print_table($val,$level-1, $_callstack);
}elseif(is_null($val)){
echo '<span style="color:blue">null</span>';
}elseif($val===false){
echo '<span style="color:red">false</span>';
}elseif($val===true){
echo '<span style="color:green">true</span>';
}elseif(is_numeric($val) && $val>1000000000){
echo $val,' <span style="color:gray">[',date('d-m-Y H:i:s',$val),']</span>';
}elseif($val===''){
echo '<span style="color:blue">empty string</span>';
}else{
echo $val;
}
echo '</td></tr>';
}
echo '</table>';
}else{
var_dump($mixed);
}
}
As you see, i collect serialaized object, then compare it. Serialization required, because simply comparsion recursive object throw a fatal error:
$arr=array(&$arr);
$arr==$arr; // Fatal error: Nesting level too deep - recursive dependency?
// php 5.2.9
But serialization support recursive objects! So, we should compare serialaized strings, but serialization can take a lot of tima and memory.
If you will find another method - let me know :)
I am working on a CodeIgniter application.
A part of the nav menu for my application is generated from using session data. Since, I have to print the same thing at a number of places, I wrote a function to do the printing. The file which creates the menu is given below. The function print_roles_assigned() is used a number of times in this file.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
The code given above didn't work. Out of any options, I resorted to using a $GLOBAL. An issue like this has never happened with me before and I am not sure if the use of $GLOBAL is appropriate. The new code is given below:
$GLOBALS['roles_assigned'] = $this->session->userdata('roles_assigned'); // Change made here
function print_roles_assigned() {
$output = '';
$roles_assigned = $GLOBALS['roles_assigned']; // Using the global variable inside function
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
I would like to know:
Why my initial code failed to work?
Is the use of $GLOBAL appropriate?
What can be an alternate method to fix this issue?
The initial code failed because your $roles_assigned in not injected. Parameterise the function to "function print_roles_assigned($roles_assigned) { .. } " to access the $roles_assigned variable.
Why my initial code failed to work?
Each function has what is called variable scope. Variables declared outside of the function are not accessible from within the function unless they are passed in as parameters, are members of a class that the function is a member of, or are explicitly declared to be global.
There are three different ways to do this, take your pick.
The easiest way to do this is to just pass the function in as a parameter I.E.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned($roles_assigned) {
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
Another option is to make $roles_assigned a member of the class, I.E.
$this->roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
$output = '';
if ($this->roles_assigned)
{
foreach ($this->roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
The other option (not recommended) is to use the global keyword I.E.
$roles_assigned = $this->session->userdata('roles_assigned');
function print_roles_assigned() {
global $roles_assigned;
$output = '';
if ($roles_assigned)
{
foreach ($roles_assigned as $role) {
$output .= '<li>' . anchor('main/home/'.$role->role_name, $role->rol
e_name) . '</li>';
}
}
else
{
$output .= '<li>No roles have been assigned.</li>';
}
return $output;
}
This sounds like a scope issue. Try using $this->roles_assigned for your reference to that array.
IMO, it's not good-practise to use GLOBAL in this way.