cakephp saveMany using $fieldList (no form) - cakephp

I have this $data array: (built on a shell, not a form)
(debugged here)
array(
(int) 0 => array(
(int) 0 => 's511013t',
(int) 1 => 'id3422',
(int) 2 => '1'
),
(int) 1 => array(
(int) 0 => 's511013t',
(int) 1 => 'id3637',
(int) 2 => '1'
)
)
And using saveMany :
$this->Dir->saveMany($data, array( 'validate' => 'false', 'fieldList' => array('name','dir_dataname', 'project_id')));
Saving fails with no error.
I'm not sure if my $data array is well formatted, (I'm confused whether it should have another level) I built it from sql selects, etc. However it does contain all info I need saved, single model.
I'm running all this from a Shell and it does work to save a single record provided the field names everytime:
// this works
$this->Dir->save(array('name' => $data[0][0], 'project_id' => $data[0][2], 'dir_dataname' => $data[0][1]));
Already read Saving your data, and I'd really like to use saveMany and a fieldList due to my custom $data format. (I wouldn't like to have to insert field names on my $data).
(no sql_dump to show since is pretty cumbersome to get it from a shell task)
I've spent all evening trying to figure it out, can you point me in the right direction, Please?

IMHO, the keys in each arrays are not valid fields in your database table. They should represent the same name as your table field.
When you build the array from sql, the output should look like these - an associative array:
array(
(int) 0 => array(
(string) name => 's511013t',
(string) dir_dataname => 'id3422',
(string) project_id => '1'
),
(int) 1 => array(
(string) name => 's511013t',
(string) dir_dataname => 'id3637',
(string) project_id => '1'
)
)
Cake2.0 Docs
$this->Dir->saveMany($data);

You can get the log via
debug($this->Dir->getDataSource()->getLog());
It looks as if you are using fieldList incorrectly. fieldList is a list of fields that are to be whitelisted for saving to the database, not a "mapping" like you are using.
You need to specify field => value pairs in the array for each record, not numerical indexes. I may be wrong, but I've never seen that and it doesn't look to be that way according to docs.

Related

Automatically adding additional Records into HABTM table in CakePhp

Iam confused about a problem. i will describe it
I am using HABTM first time in cakephp,also i am not too much familiar with cakephp 2.4.6
I have
MediaOrg- model, media_orgs - table name
table fields- id,name
public $hasAndBelongsToMany = array(
'className' => 'ContactPerson',
'joinTable' => 'contact_people_media_orgs',
'foreignKey' => 'media_org_id',
'associationForeignKey' => 'contact_person_id'
);
ContactPerson -model contact_person- table name
table_fields - id,name,designation,contact_number,ladline
public $hasAndBelongsToMany = 'MediaOrg'
ContactPeopleMediaOrg -model , table name-contat_people_media_orgs
table_fields - contact_person_id ,media_org_id
//now in controller saving values for media_org table
$this->MediaOrg->save($this->request->data)
$media_org_id=$this->MediaOrg->id;
//next in controller saving values for contact_person table
$this->ContactPerson->save($this->request->data)
$mcontact_person_id=$this->ContactPerson->id;
//next saving id's into many-to-many table
$contact_person_mediaorg_table=array('contact_person_id'=>$contact_person_id,
'media_org_id'=>$media_org_id );
$this->ContactPeopleMediaOrg->save($contact_person_mediaorg_table);
everything is working fine. i dont know what happends in the common table
contact_person_media_org , the data is adding 3 tomes.
first time it adding correct id's and next each time it addiing the mobile number and land number of contact person with media_org_id
when i debug it using getDataSource(), i can find that some param is passing to that common table and adding to it. i dont know how it happening
(int) 6 => array('query' => 'INSERT INTO `go4ad`.`contact_people_media_orgs`
(`media_org_id`, `contact_person_id`) VALUES (?,?)',
'params' => array(
(int) 0 => '30',
(int) 1 => '55555555'
),
'affected' => (int) 0,
'numRows' => (int) 0,
'took' => (float) 1
Also i can find that some BEGIN and COMMIT keywords are there.
Actually What is happening..if anyone can help me..pls pls help me. iam stucking
You should use saveAssociated(). Overall, your process should generate something like this:
$this->request->data = array(
'MediaOrg' => array(
'id' => $media_org_id,
),
'ContactPerson' => array(
0 => $first_person_id,
1 => $second_person_id,
2 => $thurd_person_id,
),
);
$this->MediaOrg->saveAssociated($this->request->data);
And it will add rows to your HABTM relation table (media_organization_contact_persons). Now, this works when you have the rows already added to the database, and you want to add the connections. If you want to add data to the tables in the same time, or whatever that this answer doesn't cover for you, you can read this article.

Cakephp value from array

I've read many similar topics here but not one helps me with problem.
i'm trying to get sections_id value from query in controller.
$query_id = "SELECT sections_id FROM sections WHERE name='".$table_name."'";
debug($id = $this->Info->query($query_id)); die();
there is debug result
array(
(int) 0 => array(
'sections' => array(
'sections_id' => '14'
)
)
)
and i tried in controller get value of id typing $id['sections']['sections_id'], or
$id['sections_id'] and many other types, nothing works. Do you have any idea ?
use $id[0]['sections']['sections_id'] to access it
For one result use
$data[0]['sections']['sections_id']
If query returns more than one result the use below code:
foreach($id as $data){
echo $data['sections']['sections_id']
}
Look for array index's carefully! Iinjoy

Dynamically Build a SQL Where Clause with the IN Keyword

I'm using cakephp 2.3.0. Summary - In my controller, I have a query where it returns one or more id values. Then, I want to use those id values in my next query, with the SQL IN keyword. I know conceptually what I want to accomplish. I think I'm doing this the correct way in CakePHP, but I could be wrong. I'm just not sure on the coding piece to dynamically build my IN clause.
Here is my code snippet from my controller:
$this->set('userIDs', $this->Activity->ActivitiesOfInterest->find('all',
array (
'conditions' => array ('ActivitiesOfInterest.activities_id' => $id),
'fields' => array ('ActivitiesOfInterest.user_id'))));
The above code is fine as I get the value or values that I would expect. In the code below, I have hard-coded this piece, array(3, 4), which is equivalent to the SQL IN keyword. The values 3, 4 would be stored in the userIDs array. But, this is where I'm not sure how to dynamically build the values of 3 and 4, from the array in the above code. Of course, 3 and 4 may not always be the values because it just depends on what is in the database. I think I need to loop through the array and build up my list of id's. I'm still somewhat new to CakePHP and I'm guessing this is an easy answer for the experienced folks.
And, yes I actually do want to perform a deleteAll operation, based on my use case.
$this->Activity->ActivitiesOfInterest->deleteAll(
array('ActivitiesOfInterest.user_id' => array(3, 4)), false);
Thank you, much appreciated.
You can also do this by using sub query for deleteALL query.
$conditionsSubQuery['ActivitiesOfInterest.activities_id'] = $id;
$db = $this->Financial->getDataSource();
$subQuery = $db->buildStatement(
array(
'fields' => array('ActivitiesOfInterest.user_id'),
'table' => $db->fullTableName($this->Activity->ActivitiesOfInterest),
'alias' => 'ActivitiesOfInterest',
'offset' => null,
'joins' => array(),
'conditions' => $conditionsSubQuery,
'order' => null,
'group' => null
),$this->Activity->ActivitiesOfInterest
);
$subQuery = ' ActivitiesOfInterest.user_id IN (' . $subQuery . ')' ;
$subQueryExpression = $db->expression($subQuery);
$conditions[] = $subQueryExpression;
$result = $this->Activity->ActivitiesOfInterest->deleteAll(compact('conditions'));
You don't need to use $this->set(), unless you need those user-ids inside your view;
The Hash::extract() may be helpfull here.
// Find the user-ids
$result = $this->Activity->ActivitiesOfInterest->find('all', array (
'conditions' => array (
'ActivitiesOfInterest.activities_id' => $id
),
'fields' => array (
'ActivitiesOfInterest.user_id'
)
));
if ($result) {
// 'extract' just the user-ids from the results
$userIds = Hash::extract($result, '{n}.ActivitiesOfInterest.user_id');
$this->Activity->ActivitiesOfInterest->deleteAll(
array(
'ActivitiesOfInterest.user_id' => $userIds
),
false
);
}

CakePHP: Date Range

Is there a better way for me to calculate the following (I'm trying to pull all "Action Items" from yesterday and store them in "paste_due", and all action items for today and store them in "today") - This is inside of my "Agents" controller (Agent 'hasMany' ActionItem and ActionItem 'belongsTo' Agent):
public function planner() {
$yesterday = date("Y-m-d 23:59:59", strtotime("yesterday"));
$conditions = array('ActionItem.due <' => $yesterday, 'ActionItem.agent_id' => '1');
$this->set('past_due', $this->Agent->ActionItem->find('all', array('conditions' => $conditions)));
$today = date("Y-m-d 00:00:00", strtotime("today"));
$today_end = date("Y-m-d 23:59:59", strtotime("today"));
$conditions = array('ActionItem.due >' => $today, 'ActionItem.due <' => $today_end, 'ActionItem.agent_id' => '1');
$this->set('today', $this->Agent->ActionItem->find('all', array('conditions' => $conditions)));
}
The above works, but I'm not for sure if it's the best way to go about i..
There would be room for some improvement (though as you say, the current code should work, so it's just some of my thoughts).
First of all, if you're only going to check against times like 00:00:00 and 23:59:59, drop the times altogether and just use a DATE field rather than a DATETIME field. It makes checking much easier as you don't have to worry about times. (If the times are essential for other parts of your application, then the below example code should be adjusted accordingly.)
Furthermore I'd use the DateTime functions of PHP rather than the date() with strtotime(), mainly because it's pretty much a habit of mine whenever I work with date/time data. This is because DateTime adds a lot of possibilities and flexibility to your date and time data without too much hassle. Something like this is what I'd probably go for:
public function planner() {
// Set the DateTime object (defaults to current date/time)
$today = new DateTime();
// Overdue actions (everything older than today)
$overdue = $this->Agent->ActionItem->find('all', array(
'conditions' => array(
// Check due against a 'Y-m-d' formatted date of today.
'ActionItem.due <' => $today->format('Y-m-d'),
'ActionItem.agent_id' => '1'
)
));
// Actions due today (or in the future)
$due = $this->Agent->ActionItem->find('all', array(
'conditions' => array(
// Check due against a 'Y-m-d' formatted date of today.
'ActionItem.due >=' => $today->format('Y-m-d'),
'ActionItem.agent_id' => '1'
)
));
// Set the items
$this->set(compact('overdue', 'due'));
}

Using DISTINCT in a CakePHP find function

I am writing a CakePHP 1.2 app. I have a list of people that I want the user to be able to filter on different fields. For each filterable field, I have a drop down list. Choose the filter combination, click filter, and the page shows only the records that match.
In people_controller, I have this bit of code:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
$this->set('first_names', $first_names);
(Status = 1 because I am using a soft delete.)
That creates an ordered list of all first_names. But duplicates are in there.
Digging around in the Cookbook, I found an example using the DISTINCT keyword and modified my code to use it.
$first_names = $this->Person->find('list', array(
'fields'=>'DISTINCT first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
This gives me an SQL error like this:
Query: SELECT `Person`.`id`, DISTINCT `Person`.` first_name` FROM `people` AS `Person` WHERE `Person`.`status` = 1 ORDER BY `Person`.`first_name` ASC
The problem is obvious. The framework is adding Person.id to the query. I suspect this comes from using 'list'.
I will use the selected filter to create an SQL statement when the filter button is clicked. I don't need the is field, but can't get rid of it.
Thank you,
Frank Luke
Try to use 'group by', it works perfectry:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1'),
'group' => 'first_name'));
You're right, it seems that you cannot use DISTINCT with list. Since you don't need id but only the names, you can use find all like above and then $first_names = Set::extract($first_names, '/Person/first_name');. That will give you a array with distinct first names.
Here's how I did it in CakePHP 3.x:
$query = $this->MyTables->find('all');
$result = $query->distinct()->toArray();
You can try this.
Here this takes Person id as key, so there is no chance for duplicate entries.
$first_names = $this->Person->find('list', array(
'fields' => array('id','first_name'),
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
Using SQL grouping will also produce a distinct list. Not sure of the negative consequences if any, but it seems to work fine for me.
$first_names = $this->Person->find('list', array(
'fields' => 'first_name',
'order' => 'first_name',
'group' => 'first_name',
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
I know it is a question for CakePHP 1.2, but I was searching for that too with CakePHP version 3. And in this version there is a method to form the Query into a distinct one:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['name']
]
)
->distinct();
;
This will generate a sql query like this:
SELECT DISTINCT Persons.name AS `Persons__name` FROM persons Persons
But the distinct method is a bit mightier than just inserting DISTINCT in the query.
If you want to just distinct the result on one field, so just throwing away a row with a duplicated name, you can also use the distinct method with an array of the fields as parameter:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['id', 'name'] //it also works if the field isn't in the selection
]
)
->distinct(['name']); //when you use more tables in the query, use: 'Persons.name'
;
This will general a sql query like this (for sure it is a group query):
SELECT DISTINCT
Persons.id AS `Persons__id`, Persons.name AS `Persons__name`
FROM persons Persons
GROUP BY name #respectively Persons.name
Hope I will help some for CakePHP 3. :)
Yes the problem is that you are using a listing which designed for a id / value output. You probably will have to do a find('all') and then build the list yourself.
Yes I also tried to fetch unique results with 'list' but its not working. Then I fixed the problem by using 'all'.
In the example now on the book for version 2 it states the following:
public function some_function() {
// ...
$justusernames = $this->Article->User->find('list', array(
'fields' => array('User.username')
));
$usernameMap = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name')
));
$usernameGroups = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name', 'User.group')
));
// ...
}
With the above code example, the resultant vars would look something like this:
$justusernames = Array
(
//[id] => 'username',
[213] => 'AD7six',
[25] => '_psychic_',
[1] => 'PHPNut',
[2] => 'gwoo',
[400] => 'jperras',
)
$usernameMap = Array
(
//[username] => 'firstname',
['AD7six'] => 'Andy',
['_psychic_'] => 'John',
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
['jperras'] => 'Joël',
)
$usernameGroups = Array
(
['User'] => Array
(
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
)
['Admin'] => Array
(
['_psychic_'] => 'John',
['AD7six'] => 'Andy',
['jperras'] => 'Joël',
)
)
You have to plan your query in a slightly different way and plan your database to accommodate a list find.
In some cases, you wish to group by using some key, but you want unique element within the results.
For example, you have a calendar application with two types of events. One event on day 1rst and the other one on the 2nd day of month 1. And you want to show or rather count all the events, grouped by day and by type.
If you use only DISTINCT, it is quite difficult. The simplest solution is to group twice:
$this->Events->virtualFields['count'] = 'COUNT(*)';
$acts = $this->Activity->find('all',array(
'group' => array('DAY(Event.start)','EventType.id'),
));
Just group by the fields that you want to get distinct.. or use Set::extract() and then array_unique()
In 2.7-RC version, this is working
$this->Model1->find('list', array(
'fields' => array('Model1.field1', Model1.field1')
));

Resources