Looping with Object Operators - php

I am playing around with PHP Calendar (Corey Worrell) and had a question regarding instance looping. In order to initialize the calendar, I have to output this:
$calendar->standard('today')
->standard('prev-next')
->standard('holidays')
->attach($event1)
->attach($event2)
->attach($event3)
->attach($event4)
->attach($event5)
->attach($event6)
->attach($event7)
->attach($event8)
->attach($event9)
->attach($event10)
->attach($event11)
->attach($event12)
->attach($event13)
->attach($event14)
->attach($event15)
->attach($event16)
->attach($event17);
Each ->attach($event#) outputs an event on the calendar. I want to loop through these numerically incrementing event names but adding a for loop anywhere in that code breaks everything, outputting this error:
PHP Catchable fatal error: Argument 1 passed to
Event_Subject::attach() must be an instance of Event_Observer, null
given, called in /calendar/index.php on line 75 and defined in
/calendar/classes/event_subject.php on line 21
Here is the loop I've tried:
$calendar->standard('today')
->standard('prev-next')
->standard('holidays')
for ($inc = 0; $inc <= $number_of_events; $inc++) {
if ($inc == $number_of_events) {
->attach($$event_name);
}
else {
->attach($$event_name)
}
}
How can I loop inside of here? My events are stored in MySQL and I am doing an $number_of_events = $result->num_rows to determine the number of events returned. The ->attach($event#) would loop, repeating until the total $number_of_events is hit.

That's called method chaining. Each method of the class returns an instance of the called object via $this, allowing you to stack method calls. Method chaining is possible because the function returns a reference to your object.
Because each function in the class that supports method chaining returns the calling object, you can just re-assign the returned object back into the original $calander variable;
for ($inc = 0; $inc <= $number_of_events; $inc++) {
if ($inc == $number_of_events) {
$calander = $calander->attach($event1);
}
else {
$calander = $calander->attach($event1);
}
}
Additionally, if you wanted to iterate through variable names, you could use a variable variable inside your loop;
$variable = "event".$inc;
$calander = $calander->attach($$variable);
So this would become $event0, $event1, $event2, etc.

The problem with the loop is that there is nothing in front of the -> operator. The -> references a property of an object, but you do not provide it with an object. You could solve it by putting $calendar in front of the lonesome operators ($calendar->...), but it would still not be very pretty code.
I suggest this instead:
I think you could just add the events one by one inside the loop I assume you are already using to create the $event1, $event2, etc. I don't know what you are using to get the data out of the database or what your table structure looks like, but I will provide an example for MySQLi. It should be easy to modify for other alternatives.
//Add the standards.
$calendar->standard('today')
->standard('prev-next')
->standard('holidays');
//Connect to the database here and query for the events using MySQLi.
//Loop through the results.
while($row = $result->fetch_assoc()) {
//Create an event from the database row...
$event = calendar->event()
->condition('timestamp', $row['TIMESTAMP'])
->title('Hello All', $row['TITLE'])
->output('My Custom Event', $row['OUTPUT']);
//...and attach it.
$calendar->attach($event);
}
This is not code to be copy-pasted directly, but more of a suggestion about how to organize it.
Also, for the future, you should not name variables $name1, $name2, etc and then use $$ to reference them. Use arrays instead.

Here's the solution. Not sure why changing this to reference $calendar each line worked, but it did. Thanks everyone.
$calendar->standard('today');
$calendar->standard('prev-next');
$calendar->standard('holidays');
for ($x = 1; $x <= $number_of_events; $x++) {
$event_name = "event".$x;
$calendar->attach($$event_name);
}

Related

PHP - Get and compare row value from a different column for the same row

I'm attempting to edit a custom function and struggling to get the row value for a particular custom column ('rank_td') to compare against its other columns (rank_lw and rank_lm), all inside a HTML table.
Tried a fair few variations and can't get it going.
Any ideas?
function custom_value($cellValue, $dataColumnHeader, $rank_td_value) {
if($dataColumnHeader == "rank_lw" || $dataColumnHeader == 'rank_lm'){
$row['rank_td']->$cellValue = $rank_td_value;
if($rank_td_value == $cellValue){
$styleColor = 'color:blue;';
}else if($rank_td_value < $cellValue){
$styleColor = 'color:green;';
}else{
$styleColor = 'color:red;';
}
return $class_name.'<span style="'.$styleColor.'">'.$cellValue.'</span>';
}
return $cellValue; }
You are not calling the global variable $row which exists outside the scope of this function - hence my comment that it doesn't look like it belongs here. If you want to be able to access a variable from outside a function you need to either pass that variable in, or declare it using the global keyword. Here is a very basic example of this:
$row['some_value'] = "value1";
function scopeTest($var1) {
$row['some_value'] = $var1;//local variable $row created
}
function scopeTestTwo($var1) {
global $row;//variable outside the function
$row['some_value'] = $var1;
}
scopeTest("jam");
print_r($row);//Array ( [some_value] => value1 )
scopeTestTwo("jam");
print_r($row);//Array ( [some_value] => jam )
in your code you also have this
return $class_name.'<span....
but $classname is not defined so either it is redundant and you should remove it (because this will cause a php notice and anyway redundant code is, well, redundant) or it should be defined somewhere which means something has been missed out

how to concat a counter for an object declaration in PHP

I am trying to create multiple instances of an object as this was how the wrapper was designed to work. Now my problem is that I wanted to add a counter in the object declaration so that I will just have to loop through my data and create the necessary object for it and also loop it again for the wrapper to read them all.
Currently, I have this:
if(sizeof($product_name) > 0){
for($counter=0;$counter<sizeof($product_name);$counter++){
$lineitem.$counter = new LineItem($this->_xi);
$lineitem.$counter->setAccountCode('200')
->setQuantity($product_qty[$counter])
->setDescription($product_name[$counter])
->setUnitAmount($product_price[$counter]);
print_r($lineitem.$counter);
}
}
print_r($lineitem0);
My print_r returns nothing for both inside and outside the loop.
Your problem is not really about OOP, but more about php. You want to create dynamic variable name to store all the instances of your class you are creating, you should do:
if(sizeof($product_name) > 0){
for($counter=0;$counter<sizeof($product_name);$counter++){
${"$lineitem$counter"} = new LineItem($this->_xi);
${"$lineitem$counter"}->setAccountCode('200')
->setQuantity($product_qty[$counter])
->setDescription($product_name[$counter])
->setUnitAmount($product_price[$counter]);
print_r(${"$lineitem$counter"});
}
}
print_r(${"$lineitem" . 0});
Have a look at this question: Dynamic variable names in PHP

dynamically retrieve object method

I try to dynamically retrieve a method of a class but php throws an exception which says Undefined property: stdClass ...
and How i try to get the values
private function getExactValue($row, $name)
{
$tempRow = clone $row;
foreach( explode('->', $name) as $key => $value)
{
$temp = $tempRow->{$value};
unset($tempRow);
$tempRow = $temp;
}
return $tempRow;
}
$row is an instance of an Object (not Std one)
$name is what i need in the Object to traverse , for example when i need $row->student->gifts->totalPoint() just pass the student->gifts->totalPoint() to the method for $name parameter
can you tell me what my mistake is?
I see what you are trying to do here. My first word of advice is that you are going about what you are trying to achieve in a very hackish way. If you wanted a better way to be able to execute arbitrary methods on an unknown object, I would suggest you look into PHP's reflection capabilities.
That being said, the problem with your code would appear to be that you are trying to execute a method via string, where what you need to do is utilize the method's name. What I would suggest is that within your loop where you explode the string on ->, you try to detect if it is a method or not, and then act accordingly. That could look like this:
foreach( explode('->', $name) as $value)
{
$value_trimmed = rtrim($value, '()');
if ($value === $value_trimmed) {
// this is a property
$tempRow = $tempRow->{$value};
} else {
// this is a method
$tempRow = $tempRow->{$value_trimmed}();
}
}
You should probably also do some validation on the input as well to make sure you have valid property/method names for each segment, as well as add validation that the entire string is indeed properly formed (i.e. you don't have things like foo->->bar(())). Of course this make no mention of how to handle array like foo[0]->bar() which you might also need to accommodate.

php use value as a variable name (for a key) from an array to unpack a resultset from Drupal

I will be reusing a Drupal db_query result set unpacking function many, many times in my code for a variety of different queries - I am using O-O and as such I want to reuse it and be as 'DRY' as possible.
Therefore I have tried to strip it down to the most generic functions so that as long as the $columns supplied match the columns used in the query and similarly in the $resultset, I can loop and assign values to keys, as is shown, and return a $rows[].
I've not yet come across the issue of trying to use a variable's value as a variable name (the $key), if it's just something I should avoid entirely, please say.
foreach($this->resultSet as $aRecord) {
$c = 0;
while (isset($this->columns[$c])) {
$value = $this->columns[$c];
$rows[$i] = array(
$key[$this->columns[$c]] => $aRecord->$value,
);
$c++;
}
$i++;
}
I've read through the following and am beginning to think this is just knowledge I'm missing in my PHP experience so far.
Can I use a generated variable name in PHP?
PHP use function return value as array
https://wiki.php.net/rfc/functionarraydereferencing
It felt wrong, and someone once told me that if you have to start writing complex functions in PHP you've probably missed an available function PHP already offers.. so true... thanks to (at the time of writing...) 'MrCode' for this suggestion.
$this->sql = "SELECT foo, bar FROM foobar";
$this->result = db_query($this->sql);
if ($this->result->rowCount() > 0) {
while ($row = $this->result->fetchAssoc()) {
$this->resultArray[] = $row;
}
}

PHP: Is code like this possible?

I'm trying to have a user-defined list of game-maps. Because I don't know how many maps will be in the array at design time, I'm trying to dynamically create new variables to contain them. Is this even possible? Here's my failed attempt:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
?>
Parser says: Fatal error: Cannot access empty property
Is something like this even feasible in this manner?
There are some errors in your code:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
Since you are on the global scope here, not inside a function, there is no need for global.
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
Is some code missing here? You are not using $element within the loop, so this assignment is not needed.
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
The syntax to access a member variable is $object->variable, not $object->$variable. The latter one will evaluate $variable and use the value as variable name (E.g., if $variable = "foo", this will try to access $object->foo).
Use $map[$i]->played = $x++; instead.
When accessing the properties of a class, you don't want to use the $ in front of the property name itself.
Replace $map[$i]->$played = $x++; with $map[$i]->played = $x++; to solve the Fatal error: Cannot access empty property error.
You could override the magic methods to provide dynamic properties if you wish:
public function __get($name)
{
...
}
public function __set($name, $value)
{
...
}
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
Within each of these functions you could store the data in some internal array structure.
You don't have to use the $ when accessing properties of an instance. Simple use $map[$i]->played. Have a look on the OOP basics.

Categories