Stop getting duplicate rows on 'saveAll' in CakePHP - php

In CakePHP when I save the data with the below code, I get the data being saved as expected but I get all the data saved 2 times. The $lesson data variable does not retrieve 2 copies of the data so the save function is the problem. I tried using save in a loop and that gives the same problem. There must be something simple I am doing wrong.
http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-save-array-data-null-boolean-validate-true-array-fieldlist-array
$data=array();
$i=0;
$this->Lessondata->cacheQueries = false;
$this->Lessondata->create( );
foreach ($lessons as $item):
// $this->Lessondata->cacheQueries = false;
$data[$i]['Lessondata']['lesson_id']=$item['Lesson']['id'];
$data[$i]['Lessondata']['st_id']=$item['Student']['id'];
$data[$i]['Lessondata']['tutor_id']=$item['Tutor']['id'];
$data[$i]['Lessondata']['student_name']=$item['Student']['first_name'].' '.$item['Student']['last_name'];
$data[$i]['Lessondata']['subject']=$item['Subject']['name'];
$data[$i]['Lessondata']['tutor_name']=$item['Tutor']['first_name'].' '.$item['Tutor']['last_name'];
$data[$i]['Lessondata']['class_year']=$item['Student']['class_year'];
// debug($data[$i]);
debug($i);
$i=$i+1;
endforeach;
$this->Lessondata->saveAll($data);

Try it.
$data = array();
foreach ($lessons as $item):
$data['Lessondata'][] = array(
'lesson_id' => $item['Lesson']['id'],
'st_id' => $item['Student']['id'],
'tutor_id' => $item['Tutor']['id'],
'student_name' => $item['Student']['first_name'] . ' ' . $item['Student']['last_name'],
'subject' => $item['Subject']['name'],
'tutor_name' => $item['Tutor']['first_name'] . ' ' . $item['Tutor']['last_name'],
'class_year' => $item['Student']['class_year'],
);
endforeach;
$this->Lessondata->create();
$this->Lessondata->saveAll($data);

This works but I need to check when the duplication starts. This is a bad answer as I am allowing for a quirk. As yet there is no other answer. I am happy to take this down if someone provides a working answer.
$this->Lessondata->create();
foreach ($lessons as $item):
$ff = $this->Lessondata->find('first', array(
'conditions' => array('Lessondata.lesson_id' => $item['Lesson']['id'])
));
if (!empty($ff)) {
debug($item);
break;
}
$data[$i]['Lessondata']['lesson_id'] = $item['Lesson']['id'];
$data[$i]['Lessondata']['st_id'] = $item['Student']['id'];
$data[$i]['Lessondata']['tutor_id'] = $item['Tutor']['id'];
$data[$i]['Lessondata']['student_name'] = $item['Student']['first_name'].' '.$item['Student']['last_name'];
$data[$i]['Lessondata']['subject'] = $item['Subject']['name'];
$data[$i]['Lessondata']['tutor_name'] = $item['Tutor']['first_name'].' '.$item['Tutor']['last_name'];
$data[$i]['Lessondata']['class_year'] = $item['Student']['class_year'];
$i = $i+1;
endforeach;
debug($data);
$this->Lessondata->saveAll($data);

Related

CakePHP 3 fast insertion/updating of records

I am trying to insert/update +/- 10k rows with a foreach loop. The complete loop duration is about 3-5minutes. Are there any tips on my code to do the insertion of update faster? The $rows are retrieved from a xls file converted to domdocument.
foreach($rows as $key => $row)
{
if($key < 1){continue;}
$cells = $row -> getElementsByTagName('td');
foreach ($cells as $cell) {
$project_id = $cells[0]->nodeValue;
$title = $cells[1]->nodeValue;
$status = $cells[2]->nodeValue;
$projectmanager = $cells[3]->nodeValue;
$engineer = $cells[4]->nodeValue;
$coordinator = $cells[5]->nodeValue;
$contractor_a = $cells[6]->nodeValue;
$contractor_b = $cells[7]->nodeValue;
$gsu = $cells[9]->nodeValue;
$geu = $cells[10]->nodeValue;
$query = $this->Projects->find('all')->select(['project_id'])->where(['project_id' => $project_id]);
if ($query->isEmpty()) {
$project = $this->Projects->newEntity();
$project->title = $title;
$project->project_id = $project_id;
$project->status = $status;
$project->projectmanager = $projectmanager;
$project->engineer = $engineer;
$project->coordinator = $coordinator;
$project->contractor_a = $contractor_b;
$project->contractor_b = $contractor_a;
$project->gsu = date("Y-m-d H:i:s");
$project->geu = date("Y-m-d H:i:s");
$project->gsm = date("Y-m-d H:i:s");
$project->gem = date("Y-m-d H:i:s");
if ($this->Projects->save($project)) {
//$this->Flash->success(__('The project has been saved.'));
continue;
}else{
debug($project->errors());
}
}else{
continue;
$query->title = $title;
$query->status = $status;
$query->projectmanager = $projectmanager;
$query->engineer = $engineer;
$query->coordinator = $coordinator;
$query->contractor_a = $contractor_b;
$query->contractor_b = $contractor_a;
$query->gsu = $gsu;
$query->geu = $geu;
if ($this->Projects->save($query)) {
//$this->Flash->success(__('The project has been saved.'));
continue;
}
}
}
//$this->Flash->error(__('The project could not be saved. Please, try again.'));
}
For faster bulk inserts don't use entities but rather generate insert queries directly.
https://book.cakephp.org/3.0/en/orm/query-builder.html#inserting-data
Ello, my vriend.
The TableClass->save() method is useful when saving one single record, in your case, you should use TableClass->saveMany() instead.
For this to happen, you need to treat your entities as arrays inside your foreach.
After the foreach, you will use another method from the tableclass (newEntities) to convert the array into entities before finally save them.
Basic example:
//Lets supose our array after our foreach become something like this:
$all_records =
[
//Each item will be an array, not entities yet
[
'name' => 'I.N.R.I.',
'year' => '1987',
'label' => 'Cogumelo',
'country' => 'Brazil',
'band' => 'Sarcófago',
'line_up' => '[{"name":"Wagner Antichrist","role":"Vomits, Insults"},{"name":"Gerald Incubus","role":"Damned Bass"},{"name":"Z\u00e9der Butcher","role":"Rotten Guitars"},{"name":"D.D. Crazy","role":"Drums Trasher"}]'
],
//Another record coming in..
[
'name' => 'Eternal Devastation',
'year' => '1986',
'label' => 'Steamhammer',
'country' => 'Germany',
'band' => 'Destruction',
'line_up' => '[{"name":"Marcel Schmier","role":"Vocals, Bass"},{"name":"Mike Sifringer","role":"Guitars"},{"name":"Tommy Sandmann","role":"Drums"}]'
]
];
//Time to get the tableclass...
$albums = TableRegistry::get('Albums');
//Time to transform our array into Album Entities
$entities = $albums->newEntities($all_records);
//Now, we have transformed our array into entities on $entities, this is the variable we need to save
if(!$albums->saveMany($entities))
{
echo "FellsBadMan";
}
else
{
echo "FellsGoodMan";
}
You can read more about here

Use array to select array keys recursively

I am having a bit of trouble trying to explain this correctly, so please bear with me...
I need to be able to recursively select keys based on a given array. I can do this via a fairly simple foreach statement (as shown below). However, I prefer to do things via PHP's built in functions whenever possible.
$selectors = array('plants', 'fruits', 'apple');
$list = array(
'plants' => array(
'fruits' => array(
'apple' => 'sweet',
'orange' => 'sweet',
'pear' => 'tart'
)
)
);
$select = $list;
foreach ($selectors as $selector) {
if (isset($select[$selector])) {
$select = $select[$selector];
} else {
exit("Error: '$selector' not found");
}
}
echo $select;
See this code in action
My Question: Is there a PHP function to recursively select array keys? If there is not, is there a better way than in the example above?
If i understand , you are searching about :
http://php.net/recursivearrayiterator
and
http://php.net/recursiveiteratoriterator
And code something like that:
$my_itera = new RecursiveIteratorIterator(new RecursiveArrayIterator($my_array));
$my_keys = array();
foreach ($my_itera as $my_key => $value) {
for ($i = $my_itera->getDepth() - 1; $i >= 0; $i--) {
$my_key = $my_itera->getSubIterator($i)->key() . '_' . $my_key;
}
$my_keys[] = $my_key;
}
var_export($my_keys);
I Hope it works.

Using a foreach inside an array

I am trying to use codeigniter's active record class to fetch a value from the database that i need to insert to a table with this code
$q = $this->db->get('center_number');
$cd = $this->db->get('running_tasks');`
$ask_for_permission = array(
'messagefrom' => $le_message_from,
'messageto' => foreach ($q->result() as $row)
{
$row->center_number;
},
'messagetext' => 'The dataset'. '' .foreach ($cd->result() as $row)
{
$row->task_name;
}. ' is requesting permission to credit the account.Reply with yes to allow or no to decline.Anything else other than yes or no shall be ignored.'
);
I get the error:
unexpected 'foreach'
How can I fetch the record from the database from within $ask_for_permission array?.
// First Generate the Array
$ask_for_permission = array(
'messagefrom' => $le_message_from,
'messageto' => '',
'messagetext' => 'The dataset'. '' .foreach ($cd->result() as $row)
{
$row->task_name;
}. ' is requesting permission to credit the account.Reply with yes to allow or no to
decline.Anything else other than yes or no shall be ignored.'
);
// Second, populate it with all values of the $q->result() array
foreach ($q->result() as $row)
{
$ask_for_permission['messageto'] .= $row->center_number;
}
Try this
function msgTo() {
$str = '' ;
foreach ($r->result() as $row) {
$str .= $row;
}
return $str;
}
and replace your foreach with msgTo()
I solved it this way
$q = $this->db->get('center_number');
$le_message_from = '08009898';
$ask_for_permission = array(
'messagefrom' => $le_message_from,
'messageto' => $q->row->center_number,
'messagetext' => 'The dataset'. ' '. $this->db->query("select task_name from running_tasks limit 1")->row()->task_name .' '.'is requesting permission to credit the account.Reply with yes to allow or no to
decline.Anything else other than yes or no shall be ignored.'
);
$this->db->insert('messageout', $ask_for_permission);

Extracting and grouping database data to an array

I have a database field called "servers"
This field has a link in each row, this field content:
> http://www.rapidshare.com/download1
> http://www.rapidshare.com/download2
> http://www.rapidshare.com/download3
> http://www.megaupload.com/download1
> http://www.megaupload.com/download2
> http://www.megaupload.com/download3
> http://www.fileserve.com/download1
> http://www.fileserve.com/download2
> http://www.fileserve.com/download3
I want to create an array with all the server names, and create more array with links inside.
That's how it should be:
$servers = array(
'rapidshare' => array(
'link1' => 'http://www.rapidshare.com/download1',
'link2' => 'http://www.rapidshare.com/download2',
'link3' => 'http://www.rapidshare.com/download3'),
'megaupload' => array(
'link1' => 'http://www.megaupload.com/download1',
'link2' => 'http://www.megaupload.com/download2',
'link3' => 'http://www.megaupload.com/download3'),
'fileserve' => array(
'link1' => 'http://www.megaupload.com/download1',
'link2' => 'http://www.megaupload.com/download2',
'link3' => 'http://www.megaupload.com/download3')
);
This will do the trick: (make sure that domain is actually showing up in $domain variable though because it might be $matches[1]... I can't remember)
$newStructure = array();
foreach($links as $link) {
preg_match("/www\.([^\.])\.com/",$link,$matches);
$domain = $matches[0];
$currentLength = count($newStructure[$domain]);
if($currentLength) {
$newStructure[$domain]['link'.($currentLength+1)] = $link;
} else {
$newStructure[$domain] = array('link1'=>$link);
}
}
$server = array(
'http://www.rapidshare.com/download1',
'http://www.rapidshare.com/download2',
'http://www.rapidshare.com/download3',
'http://www.megaupload.com/download1',
'http://www.megaupload.com/download2',
'http://www.megaupload.com/download3',
'http://www.fileserve.com/download1',
'http://www.fileserve.com/download2',
'http://www.fileserve.com/download3'
);
$match = array();
$myarray = array();
foreach($server as $v) {
// grab server name
preg_match('/\.(.+)\./', $v, $match);
$serverName = $match[1];
// initialize new array if its the first link of that particular server
if (!isset($myarray[$serverName])) {
$myarray[$serverName] = array();
}
// count server array to check how many links are there, and make next link key
$linkKey = 'link' . (count($myarray[$serverName]) + 1);
// store value
$myarray[$serverName][$linkKey] = $v;
}
print_r($myarray);
Hey maybe this will help you. But i dont see the purpose of those names of the keys (link1,link2 etc..). This wont work on pagination thou.

Using foreach inside of a defined array PHP

Is there anyway to loop through an array and insert each instance into another array?
$aFormData = array(
'x_show_form' => 'PAYMENT_FORM',
foreach($aCartInfo['items'] as $item){
'x_line_item' => $item['id'].'<|>'.$item['title'].'<|>'.$item['description'].'<|>'.$item['quantity'].'<|>'.$item['price'].'<|>N',
}
);
Not directly in the array declaration, but you could do the following:
$aFormData = array(
'x_show_form' => 'PAYMENT_FORM',
'x_line_item' => array(),
);
foreach($aCartInfo['items'] as $item){
$aFormData['x_line_item'][] = $item['id'].'<|>'.$item['title'].'<|>'.$item['description'].'<|>'.$item['quantity'].'<|>'.$item['price'].'<|>N';
}
Yes, there is a way ; but you must go in two steps :
First, create your array with the static data
And, then, dynamically add more data
In your case, you'd use something like this, I suppose :
$aFormData = array(
'x_show_form' => 'PAYMENT_FORM',
'x_line_item' => array(), // right now, initialize this item to an empty array
);
foreach($aCartInfo['items'] as $item){
// Add the dynamic value based on the current item
// at the end of $aFormData['x_line_item']
$aFormData['x_line_item'][] = $item['id'] . '<|>' . $item['title'] . '<|>' . $item['description'] . '<|>' . $item['quantity'] . '<|>' . $item['price'] . '<|>N';
}
And, of course, you should read the section of the manual that deals with arrays : it'll probably help you a lot ;-)
You mean something like this :
$aFormData = array(
'x_show_form' => 'PAYMENT_FORM',
'x_line_item' => array(),
);
foreach($aCartInfo['items'] as $item) {
$aFormData['x_line_item'][] = implode('<|>', $aCartInfo['items']).'<|>N',
}

Categories