PHP: Saving foreach data within foreach - php

I am trying to save sets of data, through these models.
Model 1: Service
Generates a series of service dates.
Model 2: Response
For each service entry, user is required to add a set number of responses.
So, I'd like to save multiple service entries for multiple response. The code is fairly self explanatory, but I can add more information if required. I can't find an easy solution to do this, though I feel it's fairly straight forward.
if (isset($_POST['Service'], $_POST['Response']))
{
$model->attributes = $_POST['Service'];
$valid = $model->validate();
// date manipulation
$start = new DateTime($model->date_booked);
$start->format('Y-m-d');
$end = new DateTime($model->end_date);
$end->format('Y-m-d');
$interval = DateInterval::createFromDateString($model->interval);
$range = new DatePeriod($start, $interval, $end);
if ($valid)
{
foreach ($range as $key => $value)
{
$schedule = new Service;
$schedule->attributes = $_POST['Service'];
$schedule->date_booked = $value->format('Y-m-d');
// If I were to save here, the following, Response Model
// will not be validated!
// $schedule->save();
foreach ($_POST['Response'] as $j => $k)
{
$response[$j] = new Response;
$response[$j]->attributes = $_POST['Response'][$j];
// If I were to save the Service Models here,
// evidently, entries are doubled up!
// $service->save();
$response[$j]->service_id = $service->id;
$valid = $response[$j]->validate() && $valid;
// $response[$j]->save();
}
}
}
}
Thank you!

I had to just run through, yet another foreach loop, to get this working. Yes, I do feel like I am iterating the loops, so if someone have another elegant solution, by all means share them to me. :-)
For now, this is done.
if (isset($_POST['Service'], $_POST['Response']))
{
// Assign and validate Service mcrypt_module_is_block_algorithm
$model->attributes = $_POST['Service'];
$valid = $model->validate();
// date manipulation
$start = new DateTime($model->date_booked);
$start->format('Y-m-d');
$end = new DateTime($model->end_date);
$end->format('Y-m-d');
$interval = DateInterval::createFromDateString($model->interval);
$range = new DatePeriod($start, $interval, $end);
// Assign and Validate Response Populated questions
foreach ($_POST['Response'] as $j => $k)
{
$response[$j] = new Response('populate'); // populate scenario
$response[$j]->attributes = $_POST['Response'][$j];
$valid = $response[$j]->validate() && $valid;
}
if ($valid)
{
foreach ($range as $key => $value)
{
$schedule = new Service; // static model
$schedule->attributes = $_POST['Service'];
$schedule->date_booked = $value->format('Y-m-d');
$schedule->save();
foreach ($_POST['Response'] as $x => $y)
{
$response[$x] = new Response('populate'); // populate scenario
$response[$x]->attributes = $_POST['Response'][$x];
$response[$x]->service_id = $schedule->id;
$response[$x]->save();
}
}
}
}

Related

If anyone please explain the code?

I don't know how this code is running well.
$on_count=0;
$on_users=array();
foreach ($res as $t_res) {
$dteStart = new DateTime("now");
$dteEnd = new DateTime($t_res["last_seen"]);
$dteDiff = $dteStart->diff($dteEnd);
$y=$dteDiff->format("%Y");
$m=$dteDiff->format("%m");
$d=$dteDiff->format("%d");
$H=$dteDiff->format("%H");
$i=$dteDiff->format("%i");
$s=$dteDiff->format("%s");
$in_sec_res=$y*12*30*24*60*60+$m*30*24*60*60+$d*24*60*60+$H*60*60+$i*60+$s."\n";
$in_sec_cond=3*60;
if ($in_sec_res<$in_sec_cond) {
$on_count=$on_count+1;
$i=0;
foreach($t_res as $t_ress){
if ($i==2) {
$on_users[$on_count]=$t_ress;
//echo $on_names[$on_count]."**\n";
}
$i++;
}
}
}
I want an explanation (inner foreach()).
Here,
last_seen
is a random DateTime.
Or is there any other way to collect all
$t_res['name']
in an array?
The inner foreach loop is very odd. It's basically just doing the same thing as:
$on_users[$on_count] = $t_res['name'];

Replace array value with new one

I have array of array, where i want to change date format. I am trying to get it as below
foreach ($toReturn as $value) {
$start_date = new DateTime($value['start_date']);
$value['start_date'] = $start_date->format('m-d-Y');
$end_date = new DateTime($value['end_date']);
$value['end_date'] = $end_date->format('m-d-Y');
}
here format gets changed but it is not replacing array value with new one?? Why??
If your want to change the value in the foreach, you need to access it by reference.
change foreach ($toReturn as $value) to foreach ($toReturn as &$value)
You have to change value by reference:
foreach ($toReturn as &$value) {
$start_date = new DateTime($value['start_date']);
$value['start_date'] = $start_date->format('m-d-Y');
$end_date = new DateTime($value['end_date']);
$value['end_date'] = $end_date->format('m-d-Y');
}
You should use the refrence operator & to change in the original array otherwise PHP treats it as local aary which is diffrent from the original one and the changes in that local array will not reflects to original array.
foreach ($toReturn as &$value) {
$start_date = new DateTime($value['start_date']);
$value['start_date'] = $start_date->format('m-d-Y');
$end_date = new DateTime($value['end_date']);
$value['end_date'] = $end_date->format('m-d-Y');
}
Alternately, if you do not wish to use the "Pass by reference" method, you can use this, or even create new variable.
foreach ($toReturn as $key => $value) {
$start_date = new DateTime($value['start_date']);
$toReturn[$key]['start_date'] = $start_date->format('m-d-Y');
$end_date = new DateTime($value['end_date']);
$toReturn[$key]['end_date'] = $end_date->format('m-d-Y');
}
Note: If you wish to use pass by reference, do not forget to unset($value) after the loop which is not necessary for given example.
You can also use access $toReturn[$index]
foreach ($toReturn as $index => $value) {
$start_date = new DateTime($value['start_date']);
$toReturn[$index]['start_date'] = $start_date->format('m-d-Y');
$end_date = new DateTime($value['end_date']);
$toReturn[$index]['end_date'] = $end_date->format('m-d-Y');
}

Collect 3rd level data dependent on the first two

I usually don't like to give up but it feels like this could be more efficient, but for the life of me I can't see it.
I have a Webservice from which I can request the Models, Makes and Types of Cars.
But to be able to request the Types I need the Makes and to be able to request the Makes I need the Models...
Because I need ALL Types (last level) to iterate over them and use them in a different piece of functionality I need to make these 3 steps.
The only problem: my current code takes about 3 minutes to finish and it feels incorrect because of Big O..
If you guys could make this more efficient I would be forever gratefull:
$cars = [];
$makes = getMakes()['makes']['Make'];
$models = [];
$types = [];
$allTypes = [];
$timeStart = microtime(true);
// Takes waaaaaay too long
foreach ($makes as $key => $make) {
$cars[$key]['makeName'] = $make['makename'];
$cars[$key]['makeCode'] = $make['makecode'];
$models = getModels($make['makecode'])['models']['Model'];
foreach ($models as $subKey => $model) {
if (is_array($model)) {
if (array_key_exists('modelname', $model)) {
$cars[$key]['models'][$subKey]['modelName'] = $model['modelname'];
}
if (array_key_exists('modelcode', $model)) {
$cars[$key]['models'][$subKey]['modelCode'] = $model['modelcode'];
}
$types = getTypes($model['modelcode']);
foreach ($types as $ssKey => $type) {
if (is_array($type)) {
if (array_key_exists('typecode', $type)) {
$cars[$key]['models'][$subKey]['types'][$ssKey]['typeCode'] = $type['typecode'];
$allTypes[] = $type['typecode'];
}
}
}
}
}
}
$timeEnd = microtime(true);
print_r(($timeEnd - $timeStart) / 60); // 3.228285531203 (~3 minutes)
// print_r($cars);

PHP - How to limit a foreach loop?

I have maybe some stupid question.
Here is my code:
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('group_id', $groupId);
$LimitLoop = 50;
foreach($customers as $customer)
{
$email=$customer->getEmail();
$CustomerPhone = $customer->getPrimaryBillingAddress()->getTelephone();
$CustomerName = $customer->getName();
$CustomerEmail = $customer->getEmail();
if($EnableSMSNotification==1 && $smstext!="") {
$api = new TextMagicAPI(array(
"username" => $TextMagicUsername,
"password" => $TextMagicPassword
));
// Use this number for testing purposes. This is absolutely free.
$phones = array($CustomerPhone);
$results = $api->send($smstext, $phones, true);
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$sql_insert = "insert into VivasIndustries_SmsHistory values ('','$CustomerName','$CustomerPhone','$CustomerEmail','$smstext',NOW())";
$write->query($sql_insert);
}
}
This is a simple foreach loop.
How can i limit it to the value pointed in $LimitLoop ?
How can i fetch only a limited number of results in this loop ?
Thanks in advance!
If using a for loop is out of the question then you would need to manually add an incrementing counter to perform the same logic. Something like this:
$LimitLoop = 50;
$i = 0;
foreach ($customers as $customer) {
if ($i++ >= $LimitLoop) {
break;
}
// the rest of the loop
}
you can save the variable $i from the other examples if you use something like this
$LimitLoop = 50;
foreach ($customers as $customer) {
/* your code to run */
/* ..... */
/* at the bottom */
$LimitLoop--;
if ($LimitLoop===0) {
break;
}
}
It's pretty simple:
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('group_id', $groupId);
$LimitLoop = 50;
$counter = 0; //Add a means of counting how many times it's been through the loop
foreach($customers as $customer)
{
$email=$customer->getEmail();
$CustomerPhone = $customer->getPrimaryBillingAddress()->getTelephone();
$CustomerName = $customer->getName();
$CustomerEmail = $customer->getEmail();
if($EnableSMSNotification==1 && $smstext!="") {
$api = new TextMagicAPI(array(
"username" => $TextMagicUsername,
"password" => $TextMagicPassword
));
// Use this number for testing purposes. This is absolutely free.
$phones = array($CustomerPhone);
$results = $api->send($smstext, $phones, true);
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$sql_insert = "insert into VivasIndustries_SmsHistory values ('','$CustomerName','$CustomerPhone','$CustomerEmail','$smstext',NOW())";
$write->query($sql_insert);
}
$counter++; //Increment the counter
if($counter >= $LimitLoop) break; //Break the loop if we have enough results
}
You'd either want to use a break statement or use a for loop that runs up to $LimitLoop.
For loop (I use array_keys function as $customers could be an associate array or have missing numeric keys, etc. Indexing the array of keys (which will have numeric ordering) then assures we always get the next key):
$keys = array_keys($customers);
for ($i = 0; $i < $LimitLoop; $i++) {
$customer = $customers[$keys[$i]];
// the rest of your code
}
Note: You would have to also insert some more logic to check that you do have 50 customers with the above loop as else it'll start throwing warnings about accessing invalid offsets in the array.
break:
$i = 0;
foreach ($customers as $customer) {
// your code
$i++;
if ($i >= $LimitLoop) {
break;
}
}

how to use three objects of an array at a time in php

I have an array called emp_rec with more than 100 employees and each employee having around 60 fields, am using the following method to use one employee at a time...
foreach($emp_rec as $obj) {
$name = $obj->get_empname();
//.....
......///
}
Now am planning to use three employees at a time in a single loop,
How can i do this...?
You could try this:
$current = Array();
while(($current[0] = array_shift($emp_rec))
&& ($current[1] = array_shift($emp_rec))
&& ($current[2] = array_shift($emp_rec))) {
// do stuff here
}
if( $current[0]) {
// there were records left over, optionally do something with them.
}
Try something like this:
for ($i = 0; $i < count($emp_rec); $i+=3) {
$emp1 = $emp_rec[$i];
$emp2 = $emp_rec[$i+1];
$emp3 = $emp_rec[$i+2];
}
Here you can iterate in one time on same multi objects. Easy to adapt.
<?php
// Example of class
class A {
public $a = 'a';
public $b = 'b';
public $c = 'c';
}
$obj1 = new A; // Instantiate 3 objects
$obj2 = new A;
$obj3 = new A;
$objs = array((array)$obj1, (array)$obj2, (array)$obj3); // Array of objects (cast in array)
foreach ($objs[0] as $key => $value) {
echo $objs[0][$key];
echo $objs[1][$key];
echo $objs[2][$key];
}
Output aaabbbccc
What about :
$GROUP_SIZE = 3;
$emp_count = count($emp_rec);
for ($i=0; $i<$emp_count; $i+=$GROUP_SIZE) {
for ($j=0; $i+$j<$emp_count && $j<$GROUP_SIZE; $j++) {
$current = $emp_rec[$i+$j];
$name = $current->get_empname();
}
}
If you need to manipulate 3 or N employees at a time, it would let you know in which "group" the current employee is.

Categories