Constructing Arrays Programmatically - php

I'm writing a PHP web app that uses XML documents from an API. I have to construct many products from the returned XML data.
What I'm doing right now is using xpath and a loop to pull all of the objects into an array of sub-arrays. Then I loop through the array of arrays and pull specific arrays into their own named array. Is there a way to do this with a function or class constructor?
My current code looks something like this:
if ( $products_results_list[$key]["sChgDesc"] == "Small Box" ) {
$small_box = array(
"ChargeDescID" => $products_results_list[$key]["ChargeDescID"],
"sChgDesc" => $products_results_list[$key]["sChgDesc"],
"dcPrice" => $products_results_list[$key]["dcPrice"],
"dcTax1Rate" => ".0" . $products_results_list[$key]["dcTax1Rate"],
"dcInStock" => $products_results_list[$key]["dcInStock"],
);
}
After writing the above if statement about 8 times, with many more times needed, I'm thinking there must be a better practice than just writing everything out.
I want to do something like:
product_constructor($argument, $product_name) {
if ( $arguement ) {
$product_name = array(
"ChargeDescID" => $products_results_list[$key]["ChargeDescID"],
"sChgDesc" => $products_results_list[$key]["sChgDesc"],
"dcPrice" => $products_results_list[$key]["dcPrice"],
"dcTax1Rate" => ".0" . $products_results_list[$key]["dcTax1Rate"],
"dcInStock" => $products_results_list[$key]["dcInStock"],
);
}
and then just call the function or constructor as needed like:
product_constructor( '$products_results_list[$key]["sChgDesc"] == "Small Box"', '$small_box');
I actually tried the above code, but it was throwing errors. Despite working with PHP daily, I still don't know much about constructors, and figured this might be the perfect opportunity to learn how to do this correctly.
I'm not sure if classes are the right choice for this since I'm going to need to pull the products themselves into product package classes later.

Related

Return Different PHP Array Values Based on A User ID-Related Constant

I am working with an array of tokens for an HTML template. Two of them ('{SYS_MENU}' and '{SUB_MENU}') are used to generate control buttons for the web application. Right now the buttons show up on the login page before the user's credential's are validated, and I need to change the code so that the buttons are hidden until after users login and reach the main menu. When someone types the http: address into their browser and arrives at the login page the system starts a session for them in the MySQL sessions table with USER_ID = 0. After they login the USER_ID changes to whatever number was assigned to them at initial registration (Example: USER_ID = 54), and after they logout at the end of the session back to 0. Tying this constant to the buttons seems like the best solution and I have found it to work in the past under similar circumstances.
Here is the original array:
$template_vars = array(
'{LANG_DIR}' => $lang_text_dir,
'{TITLE}' => theme_page_title($section),
'{CHARSET}' => $charset,
'{META}' => $meta,
'{GAL_NAME}' => $CONFIG['gallery_name'],
'{GAL_DESCRIPTION}' => $CONFIG['gallery_description'],
'{SYS_MENU}' => theme_main_menu('sys_menu'),
'{SUB_MENU}' => theme_main_menu('sub_menu'),
'{ADMIN_MENU}' => theme_admin_mode_menu(),
'{CUSTOM_HEADER}' => $custom_header,
'{JAVASCRIPT}' => theme_javascript_head(),
'{MESSAGE_BLOCK}' => theme_display_message_block(),
);
The first thing I did was to work with the references directly in the HTML template. I saw an example on w3schools that made it look like you could just type a PHP script into HTML and have it resolve. That didn't do anything except echo a bunch of text randomly into the page. I then found another citation that said you had to activate the PHP with an .HTACCESS entry before it would work directly in HTML. But that didn't close the deal either.
I know that changing '{SYS_MENU}' and '{SUB_MENU}' values in the array to => "", produces the results that I want (I.E. make the menu buttons disappear). So my next thought was I'll create an IF statement that returns two versions of the array based on circumstances, something like:
if(USER_ID != 0)
{
return $template_vars = //FIRST VERSION OF ARRAY WITH FULL VALUES//
}
else
{
return $template_vars = //SECOND VERSION OF ARRAY WITH ONLY => ""//
}
But all that did was cause the application load to terminate at a white screen with no error feedback.
My most recent attempt came from something I read here on Stack Overflow. I know that you cannot put IF statements into an array. But the article at this link described a workaround:
If statement within an array declaration ...is that possible?
So I rewrote the array as follows:
template_vars = array(
'{LANG_DIR}' => $lang_text_dir,
'{TITLE}' => theme_page_title($section),
'{CHARSET}' => $charset,
'{META}' => $meta,
'{GAL_NAME}' => $CONFIG['gallery_name'],
'{GAL_DESCRIPTION}' => $CONFIG['gallery_description'],
'{SYS_MENU}' => ('USER_ID != 0' ? theme_main_menu('sys_menu') : ""),
'{SUB_MENU}' => ('USER_ID != 0' ? theme_main_menu('sub_menu') : ""),
'{ADMIN_MENU}' => theme_admin_mode_menu(),
'{CUSTOM_HEADER}' => $custom_header,
'{JAVASCRIPT}' => theme_javascript_head(),
'{MESSAGE_BLOCK}' => theme_display_message_block(),
);
But that seems to have no effect at all. The application doesn't crash but the buttons are static whether you are logged in or logged out.
My question is: What am I missing? I can see that this is possible. But I've been trying things for a day and a half and just seem to be dancing around the solution. Your thoughts would be greatly appreciated.
The problem here is that you are calling return. With a global include file like this there is not context to return to so the application terminates. What you want to do is just assign the variables.
if(USER_ID != 0)
{
$template_vars = //FIRST VERSION OF ARRAY WITH FULL VALUES//
}
else
{
$template_vars = //SECOND VERSION OF ARRAY WITH ONLY => ""//
}

Using an array (or xml) to program a function

Ultimate Goal
Is to make something like Magento offers - basically a logic builder, and as shown by this post on Stackoverflow: jQuery (or any web tool) Nested Expression Builder So far I have made jQuery to build a tree and get the data that I want the builder to use, check, and set. Now I just need to parse the checks and add it into various places in a script I'm making - but I am unsure how to process it dynamically so that these checks can be performed, which will lead to some actions occurring/data being changed automatically.
Maybe we can call this dynamic expression processing?
Original Post
Forgive me, I know what I would like to do, but have little idea how to do it - so I'm looking for some inspiration. I have allowed a multidimensional array to be generated, and the array would contain certain 'commands' and logic functions, and when a condition is true it is executed.
In it's most basic form, the array would contain a set of if statements, where if the statement were true, then would would proceed to the next array item and go down a level, if it were false, then you'd proceed to the next array item with no children (an unmarried sibling, i guess we could call it). Once there is nothing left to process, since nothing is true, then nothing would happen.
I'd imagine that maybe the best way to 'feed' the data in would be via XML - though would this be possible, I mean, to keep going deeper, else go down, essentially until there is a true condition?
Basically, the array takes the following form (though I not 100% sure I've written it correctly, but I think it looks right :s):
[0][0] => array('function' => 'if', 'check' => 'day', 'condition' => 'equals', 'value' => '3');
[0][1][0] => array('function' => 'set', 'name' => 'date_day', 'value' => 'wednesday');
[1][0] => array('function' => 'if', 'check' => 'day', 'condition' => 'equals', 'value' => '4');
[1][1][0] => array('function' => 'set', 'name' => 'date_day', 'value' => 'thursday');
So the above would be - if day=3, then set date_day as wednesday; else if day=4, then set date_day as thursday
Which I'd imagine would correspond to (though i have no idea if you can sub item):
<items>
<item>
<function>if</function>
<check>day</check>
<condition>equals</condition>
<value>3</value>
<item>
<function>set</function>
<name>date_day</name>
<value>wednesday</value>
</item>
</item>
<item>
<function>if</function>
<check>day</check>
<condition>equals</condition>
<value>4</value>
<item>
<function>set</function>
<name>date_day</name>
<value>thursday</value>
</item>
</item>
</items>
Which would basically make the following statements in a function of some sort:
function ($current_data){
LOOP
if(FUNCTION == "if"){
if(CHECK CONDITION VALUE){
**go to next item deeper in the chain**
} else {
**go to sibling item**
}
} else if(FUNCTION == "set"){
define(NAME, VALUE);
}
ENDLOOP
}
I know the above can be done using the date() function, but this is a very basic example. Another example could involve check to see if the colour entered was red, and if it were, then set something based on this colour, else do something else if it were blue. Another could be to set the template to be for US visitors if the US flag was clicked on. The point is that it could basically fulfil any action and do a check and give a result - basically like programming - but where the function data is feed in by PHP or XML
I'm sure there must be something out there that can accomplish this, but I just have no idea were to start exactly, so any assistance would be great - and yes I know there could be some security concerns, but I plan on having checks in place checking that the checks, conditions, values, etc are safe (so this needs to be able to be factored in).
Many many thanks!
Okay JSON vs. XML aside, here's how I would process that array...
$array = xmldecode($xml);
$resultFound = false;
$i = 0;
while(!$resultFound && $i < count($array)) {
if (myFunction($array[$i]) {
$resultFound = true;
}
$i++;
}
if (!$resultFound) {
// error condition
}
function myFunction($array) {
$function = $array[0]['function'];
switch($function) {
case 'if':
$checkVariable = $array[0]['check'];
$condition = $array[0]['condition'];
$checkValue = $array[0]['value'];
switch($checkVariable)
case 'day':
switch($condition) {
case 'equals':
if (GLOBAL_DAY == $checkValue) {
return myFunction($array[1]);
} else {
return false;
}
break;
case 'less than':
if (GLOBAL_DAY < $checkValue) {
return myFunction($array[1]);
} else {
return false;
}
break;
}
break;
}
break;
case 'set':
$setVariable = $array[0]['name'];
$setValue = $array[0]['value'];
switch($setVariable) {
case 'date_day':
GLOBAL_DATE_DAY = $setValue;
return true;
break;
}
break;
}
}
Your problem is very similar to that of form validation, so I would look at some popular jQuery form validation plugins or MVC frameworks like CakePHP. These typically all have stock building blocks for the most common validation rules that the user can easily put together and pass specific arguments to to cover most scenarios.
The notable difference between your problem and these examples is that form validation frameworks are aimed at developers, so they can simply write custom functions if they need to glue multiple rules together to form a more complex rule. However, you can still achieve something that works for probably 98% of all use cases by doing something like:
$offers = array(
'pet feed sale' => array(
'category' => array(1, 2, 3)
'total' => '>100',
'weekday' => array('mon', 'wed')
'set' => array(
'discount' => 80
'shipping' => 0
)
),
'medication sale' => array(
'category' => 4
'date' => '2012-1-28',
'set' => array(
'discount' => 50
)
)
);
And if the user needs apply more complex pricing structures then they could, for instance, break the "pet feed sale" rule into 3 offers, one for dog food, one for cat food, and one for fish food. There might be more repetition, but it makes it much easier to implement than a full parser.
Also, most non-programmers probably handle repetition a lot better than complicated logic and control flow.

PHP library for creating/manipulating fixed-width text files

We have a web application that does time-tracking, payroll, and HR. As a result, we have to write a lot of fixed-width data files for export into other systems (state tax filings, ACH files, etc). Does anyone know of a good library for this where you can define the record types/structures, and then act on them in an OOP paradigm?
The idea would be a class that you hand specifications, and then work with an instance of said specification. IE:
$icesa_file = new FixedWidthFile();
$icesa_file->setSpecification('icesa.xml');
$icesa_file->addEmployer( $some_data_structure );
Where icesa.xml is a file that contains the spec, although you could just use OOP calls to define it yourself:
$specification = new FixedWidthFileSpecification('ICESA');
$specification->addRecordType(
$record_type_name = 'Employer',
$record_fields = array(
array('Field Name', Width, Vailditation Type, options)
)
);
EDIT: I'm not looking for advice on how to write such a library--I just wanted to know if one already existed. Thank you!!
I don't know of a library that does exactly what you want, but it should be rather straight-forward to roll your own classes that handle this. Assuming that you are mainly interested in writing data in these formats, I would use the following approach:
(1) Write a lightweight formatter class for fixed width strings. It must support user defined record types and should be flexible with regard to allowed formats
(2) Instantiate this class for every file format you use and add required record types
(3) Use this formatter to format your data
As you suggested, you could define the record types in XML and load this XML file in step (2). I don't know how experienced you are with XML, but in my experience XML formats often causes a lot of headaches (probably due to my own incompetence regarding XML). If you are going to use these classes only in your PHP program, there's not much to gain from defining your format in XML. Using XML is a good option if you will need to use the file format definitions in many other applications as well.
To illustrate my ideas, here is how I think you would use this suggested formatter class:
<?php
include 'FixedWidthFormatter.php' // contains the FixedWidthFormatter class
include 'icesa-format-declaration.php' // contains $icesaFormatter
$file = fopen("icesafile.txt", "w");
fputs ($file, $icesaFormatter->formatRecord( 'A-RECORD', array(
'year' => 2011,
'tein' => '12-3456789-P',
'tname'=> 'Willie Nelson'
)));
// output: A2011123456789UTAX Willie Nelson
// etc...
fclose ($file);
?>
The file icesa-format-declaration.php could contain the declaration of the format somehow like this:
<?php
$icesaFormatter = new FixedWidthFormatter();
$icesaFormatter->addRecordType( 'A-RECORD', array(
// the first field is the record identifier
// for A records, this is simply the character A
'record-identifier' => array(
'value' => 'A', // constant string
'length' => 1 // not strictly necessary
// used for error checking
),
// the year is a 4 digit field
// it can simply be formatted printf style
// sourceField defines which key from the input array is used
'year' => array(
'format' => '% -4d', // 4 characters, left justified, space padded
'length' => 4,
'sourceField' => 'year'
),
// the EIN is a more complicated field
// we must strip hyphens and suffixes, so we define
// a closure that performs this formatting
'transmitter-ein' => array(
'formatter'=> function($EIN){
$cleanedEIN = preg_replace('/\D+/','',$EIN); // remove anything that's not a digit
return sprintf('% -9d', $cleanedEIN); // left justified and padded with blanks
},
'length' => 9,
'sourceField' => 'tein'
),
'tax-entity-code' => array(
'value' => 'UTAX', // constant string
'length' => 4
),
'blanks' => array(
'value' => ' ', // constant string
'length' => 5
),
'transmitter-name' => array(
'format' => '% -50s', // 50 characters, left justified, space padded
'length' => 50,
'sourceField' => 'tname'
),
// etc. etc.
));
?>
Then you only need the FixedWidthFormatter class itself, which could look like this:
<?php
class FixedWidthFormatter {
var $recordTypes = array();
function addRecordType( $recordTypeName, $recordTypeDeclaration ){
// perform some checking to make sure that $recordTypeDeclaration is valid
$this->recordTypes[$recordTypeName] = $recordTypeDeclaration;
}
function formatRecord( $type, $data ) {
if (!array_key_exists($type, $this->recordTypes)) {
trigger_error("Undefinded record type: '$type'");
return "";
}
$output = '';
$typeDeclaration = $this->recordTypes[$type];
foreach($typeDeclaration as $fieldName => $fieldDeclaration) {
// there are three possible field variants:
// - constant fields
// - fields formatted with printf
// - fields formatted with a custom function/closure
if (array_key_exists('value',$fieldDeclaration)) {
$value = $fieldDeclaration['value'];
} else if (array_key_exists('format',$fieldDeclaration)) {
$value = sprintf($fieldDeclaration['format'], $data[$fieldDeclaration['sourceField']]);
} else if (array_key_exists('formatter',$fieldDeclaration)) {
$value = $fieldDeclaration['formatter']($data[$fieldDeclaration['sourceField']]);
} else {
trigger_error("Invalid field declaration for field '$fieldName' record type '$type'");
return '';
}
// check if the formatted value has the right length
if (strlen($value)!=$fieldDeclaration['length']) {
trigger_error("The formatted value '$value' for field '$fieldName' record type '$type' is not of correct length ({$fieldDeclaration['length']}).");
return '';
}
$output .= $value;
}
return $output . "\n";
}
}
?>
If you need read support as well, the Formatter class could be extended to allow reading as well, but this might be beyond the scope of this answer.
I have happily used this class for similar use before. It is a php-classes file, but it is very well rated and has been tried-and-tested by many. It is not new (2003) but regardless it still does a very fine job + has a very decent and clean API that looks somewhat like the example you posted with many other goodies added.
If you can disregard the german usage in the examples, and the age factor -> it is very decent piece of code.
Posted from the example:
//CSV-Datei mit Festlängen-Werten
echo "<p>Import aus der Datei fixed.csv</p>";
$csv_import2 = new CSVFixImport;
$csv_import2->setFile("fixed.csv");
$csv_import2->addCSVField("Satzart", 2);
$csv_import2->addCSVField("Typ", 1);
$csv_import2->addCSVField("Gewichtsklasse", 1);
$csv_import2->addCSVField("Marke", 4);
$csv_import2->addCSVField("interne Nummer", 4);
$csv_import2->addFilter("Satzart", "==", "020");
$csv_import2->parseCSV();
if($csv_import->isOK())
{
echo "Anzahl der Datensätze: <b>" . $csv_import2->CSVNumRows() . "</b><br>";
echo "Anzahl der Felder: <b>" . $csv_import2->CSVNumFields() . "</b><br>";
echo "Name des 1.Feldes: <b>" . $csv_import2->CSVFieldName(0) . "</b><br>";
$csv_import2->dumpResult();
}
My 2 cents, good-luck!
I don't know of any PHP library that specifically handles fixed-width records. But there are some good libraries for filtering and validating a row of data fields if you can do the job of breaking up each line of the file yourself.
Take a look at the Zend_Filter and Zend_Validate components from Zend Framework. I think both components are fairly self-contained and require only Zend_Loader to work. If you want you can pull just those three components out of Zend Framework and delete the rest of it.
Zend_Filter_Input acts like a collection of filters and validators. You define a set of filters and validators for each field of a data record which you can use to process each record of a data set. There are lots of useful filters and validators already defined and the interface to write your own is pretty straightforward. I suggest the StringTrim filter for removing padding characters.
To break up each line into fields I would extend the Zend_Filter_Input class and add a method called setDataFromFixedWidth(), like so:
class My_Filter_Input extends Zend_Filter_Input
{
public function setDataFromFixedWidth($record, array $recordRules)
{
if (array_key_exists('regex', $recordRules) {
$recordRules = array($recordRules);
}
foreach ($recordRules as $rule) {
$matches = array();
if (preg_match($rule['regex'], $record, $matches)) {
$data = array_combine($rule['fields'], $matches);
return $this->setData($data);
}
}
return $this->setData(array());
}
}
And define the various record types with simple regular expressions and matching field names. ICESA might look something like this:
$recordRules = array(
array(
'regex' => '/^(A)(.{4})(.{9})(.{4})/', // This is only the first four fields, obviously
'fields' => array('recordId', 'year', 'federalEin', 'taxingEntity',),
),
array(
'regex' => '/^(B)(.{4})(.{9})(.{8})/',
'fields' => array('recordId', 'year', 'federalEin', 'computer',),
),
array(
'regex' => '/^(E)(.{4})(.{9})(.{9})/',
'fields' => array('recordId', 'paymentYear', 'federalEin', 'blank1',),
),
array(
'regex' => '/^(S)(.{9})(.{20})(.{12})/',
'fields' => array('recordId', 'ssn', 'lastName', 'firstName',),
),
array(
'regex' => '/^(T)(.{7})(.{4})(.{14})/',
'fields' => array('recordId', 'totalEmployees', 'taxingEntity', 'stateQtrTotal'),
),
array(
'regex' => '/^(F)(.{10})(.{10})(.{4})/',
'fields' => array('recordId', 'totalEmployees', 'totalEmployers', 'taxingEntity',),
),
);
Then you can read your data file line by line and feed it into the input filter:
$input = My_Filter_Input($inputFilterRules, $inputValidatorRules);
foreach (file($filename) as $line) {
$input->setDataFromFixedWidth($line, $recordRules);
if ($input->isValid()) {
// do something useful
}
else {
// scream and shout
}
}
To format data for writing back to the file, you would probably want to write your own StringPad filter that wraps the internal str_pad function. Then for each record in your data set:
$output = My_Filter_Input($outputFilterRules);
foreach ($dataset as $record) {
$output->setData($record);
$line = implode('', $output->getEscaped()) . "\n";
fwrite($outputFile, $line);
}
Hope this helps!
I think you need a bit more information than you supplied:
What kind of data structures would you like to use for your records and column definitions?
It seems like this is a rather specialized class that would require customization for your specific use case.
I have a PHP class that I wrote that basically does what you are looking for, but relying on other classes that we use in our system. If you can supply the types of data structures you want to use it with I can check if it will work for you and send it over.
Note: I published this answer before from a public computer and I could not get it to appear to be from me (it showed as some random user). If you see it, please ignore the answer from 'john'.
If this is text file with separated fields, - your will need write it yourself.
Probably it is not a large problem. Good organization, will save a lot of time.
Your need universal way of defining structures. I.e. xml.
Your need something to generate ... specially I prefer an Smarty templating for this.
So this one:
<group>
<entry>123</entry>
<entry>123</entry>
<entry>123</entry>
</group>
Can be easy interpreted into test with this template:
{section name=x1 loop=level1_arr}
{--output root's--}
{section name=x2 loop=level1_arr[x1].level2_arr}
{--output entry's--}
{/section}
{/section}
This is just idea.
But imagine:
You need xml
You need template
i.e. 2 definitions to abstract any text structure
Perhaps the dbase functions are what you want to use. They are not OOP, but it probably would not be too difficult to build a class that would act on the functions provided in the dbase set.
Take a look at the link below for details on dbase functionality available in PHP. If you're just looking to create a file for import into another system, these functions should work for you. Just make sure you pay attention to the warnings. Some of the key warnings are:
There is no support for indexes or memo fields.
There is no support for locking.
Two concurrent web server processes modifying the same dBase file will very likely ruin your database.
http://php.net/manual/en/book.dbase.php
I'm sorry i cant help you with a direct class i have seen some thing that does this but i can't remember where so sorry for that but it should be simple for a coder to build,
So how i have seen this work in an example:
php reads in data
php then uses a flag (E.G a $_GET['type']) to know how to output the data E.G Printer, HTML, Excel
So you build template files for each version then depending on the flag you load and use the defined template, as for Fixed Width this is a HTML thing not PHP so this should be done in templates CSS
Then from this you can output your data how ever any user requires it,
Smarty Templates is quite good for this and then the php header to send the content type when required.

bad practice? what's it 'called'

in PHP, I'm considering doing something like this:
function foo(){
echo 'bar';
}
$fn = 'foo';
$fn();
It works, but is it considered bad practice?
I have an multidimensional array of elements that each have a corresponding function. I would like to store that function name, and call the corresponding functions for each element when traversing the array.
something like:
function render_el1(){ echo 'et';}
function render_el2(){ echo 'to';}
$elements = array(
'el_1' => array(
'name' => 'Element One'
, 'func' => 'render_el1'
)
, 'el_2' => array(
'name' => 'Element Two'
, 'func' => 'render_el2'
)
);
foreach($elements as $element => $options){
$fn = $options['func'];
echo '<h1>'.$options['name'].'</h1>';
if (function_exists($fn)) {
$fn();
}
}
Any comments to this approach is highly welcome, and I'd also like to know what this method is called in programming terms.
Not sure it is bad practice, but it makes your code hard to understand : to understand your short (5 lines) example, I've had to think :-(
Using call_user_func() and other functions of the same kind could have at least one advantage : looking at the code, one would immediatly understand you are calling a function in a way that's not the one we're generally used to.
You want to register functions into an array in your second example and then call them for what looks like a render process. This is similar to using function pointers in C (or paint event callbacks etc). It is an okay approach if you don't want to/can't use polymorphism (the feature that makes OOP worthwhile).
Your approach is simpler at that stage, but will probably get more bloated if you are adding more sophisticated code.

Setting the key of an object property that is an array

Just today I noticed a strange behavior in an object model that was previously working just fine (I have checked everything possible and nothing about its configuration has changed, so I am suspecting a change to PHP version and wondering if anyone else has experience anything similar)
Until recently, I could set the keys of object properties that were arrays manually. The specific implememation of this in one of my models was contained in a gallery class that looked like this:
public function __construct($gid){
parent::__construct($gid);
$this->Photos = $this->getPhotos();
$this->AlbumCover = $this->getCover();
}
public function getPhotos(){
$sql = 'SELECT GalleryPhotoID FROM GalleryPhoto WHERE GalleryID = ?';
$params = array($this->GalleryID);
$allids = DatabaseHandler::GetAll($sql, $params);
$output = array();
foreach($allids as $id){
$gp = new GalleryPhoto($id['GalleryPhotoID']);
$output[$gp->GalleryPhotoID] = $gp;
}
return $output;
}
Irrelevant parts omitted.
Basically, I could set the array keys of the Gallery's Photos object to the individual photo's id in the database. This just made it easier to code for individual iteration and made the whole thing run smoother.
Now, no matter what I set that key to, automatic integers are generated when the foreach runs. I even tried typing a literal string in there, which theoretically should replace every iteration, but I still got incremented, automatic integers for the keys of the property Photos.
[Photos] => Array
(
[0] => GalleryPhoto Object
(
[GalleryID] => 9
[Caption] =>
[Orientation] => 0
[AlbumCover] =>
[DateAdded] => 2011-01-03 16:58:51
[GalleryPhotoID] => 63
[Thumbnail] =>
[Image] =>
[src] => http://..com/galleryImage/getImage/63
)
[1] => GalleryPhoto Object
(
[GalleryID] => 9
[Caption] =>
[Orientation] => 0
[AlbumCover] =>
[DateAdded] => 2011-01-03 16:58:51
[GalleryPhotoID] => 64
[Thumbnail] =>
[Image] =>
[src] => http://..com/galleryImage/getImage/64
)
)
Has the abillity to manually set keys within an object property that is an array been removed in some minor release and I am unaware of it? I have googled all over, looked through the PHP manual site and found no answer. Has anyone experienced anything similar? Is there a better approach I should consider? I only really went with this because it made it so much easier to implement a next/previous system via ajax requests back to the next logical id (keeping in mind that ids can be deleted between!)
Thanks!
I don't see anything wrong with what you have, and I've never experienced the behavior you describe. However, a quick solution could be to replace the assignment line with something like this:
$output[$id['GalleryPhotoID']] = $gp;
You could also echo $gp->GalleryPhotoID; to ensure that the GalleryPhotoID property can actually be accessed that way.
Lastly, you said you replaced the above line with something akin to:
$output['foobar'] = $gp;
and it still created a new entry, with integer keys, for each entry? If that's the case, then I think there may be something in the code you omitted that's causing the problem.
Facepalm all the way. The effluvium of New Year's must still be in my brain, else I would have noticed that the function I added to fetch the album cover thumbnail shuffled the array if there wasn't a photo with the AlbumCover property set!
private function getCover(){
foreach($this->Photos as $ind=>$p){
if($p->AlbumCover){
return $this->Photos[$ind];
}
}
shuffle($this->Photos); //this is the problem
return current($this->Photos);
}
I amended this to just make a local copy of the variable and shuffle that instead if no cover is set.
private function getCover(){
foreach($this->Photos as $ind=>$p){
if($p->AlbumCover){
return $this->Photos[$ind];
}
}
$Photos = $this->Photos;
shuffle($Photos);
return current($Photos);
}
I accepted and upvoted both the answer and the comment posted since your caveats lead me to my error. Thanks guys!

Categories