2

I have an array of data which contains child arrays, each child array can contain a different number of keys:

Example:

Parent array $service:

[0] => stdClass Object // 9 keys
(
[std] => 11:47
[etd] => On time
[platform] => 15
[operator] => Southern
[operatorCode] => SN
[serviceType] => train
[length] => 12
[serviceID] => 2R2kKgVAvyBh7d/FhIatXQ==
[rsid] => SN220703
)


[1] => stdClass Object // 7 keys
(
[std] => 11:47
[etd] => On time
[operator] => Southern
[operatorCode] => SN
[serviceType] => train
[serviceID] => OH2Ufaa4ToefjtmYSubfQA==
[rsid] => SN351100
)

If I dump the array for $service using:

foreach( $service as $index => $obj ){
    $keys=array_keys( get_object_vars( $obj ) );
    print_r ($keys);
}

I get:

Array
(
    [0] => std
    [1] => etd
    [2] => operator
    [3] => operatorCode
    [4] => serviceType
    [5] => length
    [6] => serviceID
    [7] => rsid
    [8] => origin
    [9] => destination
)
Array
(
    [0] => std
    [1] => etd
    [2] => operator
    [3] => operatorCode
    [4] => serviceType
    [5] => serviceID
    [6] => rsid
    [7] => origin
    [8] => destination
)

The child arrays both contain a different number of keys, the first contains 10 and the second contain 9.

I then loop through each of the child arrays and write the results to a data table:

foreach( $keys as $key ){
    ${$key}=$obj->$key;
    print_r (${$key});
}

The issue I have is if the second child array only has 9 keys, in this example "[5] => length" is missing from the second array, each successive loop writes the content of the missing key to my data table.

My question is, how can I check if the child arrays contain "[5] => length" before writing to the data table and if not present write nothing to the corresponding data table field.

Complete script:

require("../../../../sysscripts/rail/OpenLDBWS.php");
$OpenLDBWS = new OpenLDBWS("my_token");
$data = $OpenLDBWS->GetDepartureBoard(100,"$Station");
header("Content-Type: text/plain");



$results=$data->GetStationBoardResult;
$generatedAt=$results->generatedAt;
$origin_crs=$results->crs;
$message=$results->nrccMessages->message->{'_'};
$platform=$results->platformAvailable;


/* The services... */
$service=$results->trainServices->service;
if( is_array( $service ) ){

    foreach( $service as $index => $obj ){
        $keys=array_keys( get_object_vars( $obj ) );
        print_r ($keys);

        foreach( $keys as $key ){
            ${$key}=$obj->$key;
            //print_r (${$key});
        }

        $origin_location=$origin->location->locationName;
        $generatedAt = date("Y-m-d H:i");
        $dest_location=$destination->location->locationName;
        $crsName=$destination->location->crs;
        $via=$destination->location->via;


        $insertSQL = sprintf("INSERT INTO UKRail_departboards (RecordDate, ServiceID, Origin_location, Origin_crs, Platform, ScheduleTime, Estimated, Dest_location, Dest_crs, Operator, Message, IsCancelled, CancelReason, DelayedReason, DeleteCode, NoCarrages, Via, DeleteTime) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
        GetSQLValueString($_POST['RecordDate']= $generatedAt, "date"),
        GetSQLValueString($_POST['ServiceID'] = $serviceID, "text"),
        GetSQLValueString($_POST['Origin_location'] = $origin_location, "text"),
        GetSQLValueString($_POST['Origin_crs'] = $origin_crs, "text"),
        GetSQLValueString($_POST['Platform'] = $platform, "text"),
        GetSQLValueString($_POST['ScheduleTime'] = $std, "text"),
        GetSQLValueString($_POST['Estimated'] = $etd, "text"),
        GetSQLValueString($_POST['Dest_location'] = $dest_location, "text"),
        GetSQLValueString($_POST['Dest_crs']= $crsName, "text"),
        GetSQLValueString($_POST['Operator'] = $operator, "text"),
        GetSQLValueString($_POST['Message'] = $message, "text"),
        GetSQLValueString($_POST['IsCancelled'] = $isCancelled, "text"),
        GetSQLValueString($_POST['CancelReason'] = $cancelReason, "text"),
        GetSQLValueString($_POST['DelayedReason'] = $delayReason, "text"),
        GetSQLValueString($_POST['DeleteCode'] = $DeleteCode, "text"),
        GetSQLValueString($_POST['NoCarrages'] = $length, "text"),
        GetSQLValueString($_POST['Via'] = $via, "text"),
        GetSQLValueString($_POST['DeleteTime'] = $DeleteTime, "text"));

        mysql_select_db($database_ex, $ex);
        $Result1 = mysql_query($insertSQL, $ex) or die(mysql_error());

        }
    }
}

Many thanks in advance for your time.

9
  • i might be missing the point, but are you looking for something like php.net/count ? this will let you count the amount of elements in the array Commented Jan 30, 2018 at 12:10
  • add the last foreach in the first one Commented Jan 30, 2018 at 12:10
  • you can make an array of all the keys(hard-coded) and then inside foreach compare with current array keys and which keys are missing add corresponding value form them also Commented Jan 30, 2018 at 12:12
  • This would be easy if the entry with key 5 was just missing ... but you have a different value there in your second array, so you would have to check the values and determine their meaning first. Assuming that you know the possible keys/property names beforehand, this would be a lot easier if you didn’t convert the objects to arrays in the first place - then sth. like isset($obj->length) will help you determine whether the current object has that property or not ... Commented Jan 30, 2018 at 12:12
  • The array_search() function search an array for a value and returns the key. eg: array_search('length',$arrayname);. Commented Jan 30, 2018 at 12:12

2 Answers 2

2

The problem you face is that if the first object contains the length property, but the next does not, then the first iteration of your loop will define the $length variable with the given value, but the second iteration of the loop will not touch that variable, i.e. it will still hold the value from the first iteration.

The best way to proceed is to not create such variables, but to access to the object properties directly. If they don't exist for a given object, you will get a null value instead, which is just what you need for your SQL statement.

So, remove this code:

    $keys=array_keys( get_object_vars( $obj ) );
    print_r ($keys);

    foreach( $keys as $key ){
        ${$key}=$obj->$key;
        //print_r (${$key});
    }

And change the following:

GetSQLValueString($_POST['NoCarrages'] = $length, "text")

to:

GetSQLValueString($_POST['NoCarrages'] = $obj->length, "text")

... repeating this change for all such dynamically created variables.

Remark: unrelated to your question, but assigning values to $_POST elements goes against the purpose of this array, and moreover, you are overwriting these values in each iteration.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, if I do as you say I get an error "Cannot access empty property" on line 150 which is "GetSQLValueString($_POST['NoCarrages'] = $obj->$length, "text"),". Any ideas?
sorry, I did not remove the "$" from $length.
0

If I've understood you, then you have

  • a list of values represented as key->value pairs ($service)
  • a list of keys which are required for processing (which I'll call $required)

To solve the question you asked,

$supplied=array_keys($service);
if (count(array_intersect($supplied, $service)) == count($required)) {
    // good to go, ALL the required params are present, there may be extra ones
} else {
    print "Missing attributes:" . implode(",", 
      array_intersect(array_diff($supplied, $service), $supplied)
    );
}

However, that ignores the journey that got you to the point of having an array populated only with some named attributes, and any additional validation requirements for validation of the input. A beter solution is to define, an an attribute by attribute basis the requirements for a valid dataset:

 $validate=array(
   'std' => '^\d\d:\d\d$|^$',
   'etd' => '(^On time$|^$|^Late$|^Cancelled$)',
   'platform' => '^\d*$',
   ...
 }

 function vaidate_input($service, $validate)
 {
    foreach($validate as $name=>$rgx) {
       if (!preg_match("/$rgx/i", $service[$name])) {
          return false;
       }
    }
    return true;
 }

(note that regexes also work in Javascript - so provide a neat way of doing validation in both the front and backend)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.