CakePHP cake saveall not saving relation models - cakephp

I'm trying to make an object which has all the fields needed to save a Product, its n variants and its n images. But for some reason the saveAll() is not working.
I tried saving an array of products with its variants and images, but no luck. It saved only the products as well. I do have the relations set up in the models
Product.php:
public $hasMany = array(
'product_variant' => array(
'className' => 'ProductVariant',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'product_image' => array(
'className' => 'ProductImage',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'product_mercadolibre' => array(
'className' => 'ProductMercadolibre',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
ProductVariant.php:
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* #var array
*/
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
and ProductImage.php:
/**
* belongsTo associations
*
* #var array
*/
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Here is the Porduct object:
[Product] => Array
(
[product_group_id] => 418112473
[handle] => advocate-ct-circa
[title] => Advocate CT Circa
[body] => :html_body:
[vendor] => Britax
[type] => Car Seats
[tags] => 0-3m, 12-18m, 18-24m, 24+m, 3-6m, 6-12m, auto asientos, britax, car seats, Dic152015, GooglePLA, hotsale-equipo, Niña, Niño, rn-18, Unisex
[published_at] => 2015-06-24T01:02:00-05:00
[published_scope] => global
[option1_name] => Title
[option1_value] => Default Title,
[image_src] => https://cdn.shopify.com/s/files/1/0154/0015/products/circa.jpg?v=1447768099
[ProductVariant] => Array
(
[variant_id] => 1096438833
[title] => Default Title
[option1_name] => Default Title
[option2_name] =>
[option3_name] =>
[variant_sku] => E9LT95Q - E1A265Q
[variant_grams] => 0
[variant_inventory_tracker] => shopify
[variant_inventory_qty] => 4
[variant_inventory_policy] => deny
[variant_fulfillment_service] => manual
[variant_price] => 8999.00
[variant_compare_at_price] =>
[variant_requires_shipping] => 1
[variant_taxable] =>
[variant_barcode] =>
[variant_image] => 1151565069
[variant_weight_unit] => kg
)
[PorductImage] => Array
(
[variant_image_id] => 1225124
[variant_image] => https://cdn.shopify.com/s/files/1/0154/0015/products/2780-ca4_2d26fff2-368d-4271-bd13-c344b5d08fb7.jpg?v=1447768100
)
)
Here is the code I used to save the product object.
$this->Product->create();
if ($this->Product->saveAll($singleProduct)) {
} else {
echo "Fallo guardar " . $singleProduct['handle'] . "<br>";
}
$singleProduct holds the object before mentioned.
All this saves only the Product model but not the variants or images. What am I doing wrong here? D:
EDIT:
I tried saveAll() with an array of products like so:
[
{
"Product": {
"product_group_id": 418112473,
"handle": "advocate-ct-circa",
"title": "Advocate CT Circa",
"body": "HTML-Body",
"vendor": "Britax",
"type": "Car Seats",
"tags": "0-3m, 12-18m, 18-24m, 24+m, 3-6m, 6-12m, auto asientos, britax, car seats, Dic152015, GooglePLA, hotsale-equipo, Niña, Niño, rn-18, Unisex",
"published_at": "2015-06-24T01:02:00-05:00",
"published_scope": "global",
"option1_name": "Title",
"option1_value": "Default Title,",
"image_src": "https://cdn.shopify.com/s/files/1/0154/0015/products/circa.jpg?v=1447768099"
},
"ProductVariant": [
{
"variant_id": 1096438833,
"title": "Default Title",
"option1_name": "Default Title",
"option2_name": null,
"option3_name": null,
"variant_sku": "E9LT95Q - E1A265Q",
"variant_grams": 0,
"variant_inventory_tracker": "shopify",
"variant_inventory_qty": 4,
"variant_inventory_policy": "deny",
"variant_fulfillment_service": "manual",
"variant_price": "8999.00",
"variant_compare_at_price": null,
"variant_requires_shipping": true,
"variant_taxable": false,
"variant_barcode": "",
"variant_image": 1151565069,
"variant_weight_unit": "kg"
}
],
"ProductImage": [
{
"variant_image_id": 1151565069,
"variant_image": "https://cdn.shopify.com/s/files/1/0154/0015/products/circa.jpg?v=1447768099"
},
.....
]
},
{
"Product": {
"product_group_id": 418498017,
"handle": "advocate-ct-tahoe",
"title": "Advocate CT Tahoe",
"body": "HTML_BOdY",
"vendor": "Britax",
"type": "Car Seats",
"tags": "0-3m, 12-18m, 18-24m, 24+m, 3-6m, 6-12m, auto asientos, britax, car seats, Dic152015, GooglePLA, hotsale-equipo, Niña, Niño, rn-18, Unisex",
"published_at": "2015-06-24T01:02:00-05:00",
"published_scope": "global",
"option1_name": "Title",
"option1_value": "Default Title,",
"image_src": "https://cdn.shopify.com/s/files/1/0154/0015/products/tahoe.jpg?v=1447768138"
},
"ProductVariant": [
{
"variant_id": 1097451593,
"title": "Default Title",
"option1_name": "Default Title",
"option2_name": null,
"option3_name": null,
"variant_sku": "E1A265N",
"variant_grams": 0,
"variant_inventory_tracker": "shopify",
"variant_inventory_qty": 2,
"variant_inventory_policy": "deny",
"variant_fulfillment_service": "manual",
"variant_price": "8999.00",
"variant_compare_at_price": null,
"variant_requires_shipping": true,
"variant_taxable": false,
"variant_barcode": "",
"variant_image": null,
"variant_weight_unit": "kg"
}
],
"ProductImage": [
{
"variant_image_id": 1152463301,
"variant_image": "https://cdn.shopify.com/s/files/1/0154/0015/products/tahoe.jpg?v=1447768138"
},
.......
]
}
]
And Im back to square one D: It only saves the product images. Ive checked the models are corrected now. But it wont save the variants or the images.
Any thoughts on this? o.o

Your data is not structured properly. To be able to save hasMany data, you have to feed the following to saveAll():
[Product] => Array
(
[product_group_id] => 418112473
[handle] => advocate-ct-circa
[title] => Advocate CT Circa
[body] => :html_body:
[vendor] => Britax
[type] => Car Seats
[tags] => 0-3m, 12-18m, 18-24m, 24+m, 3-6m, 6-12m, auto asientos, britax, car seats, Dic152015, GooglePLA, hotsale-equipo, Niña, Niño, rn-18, Unisex
[published_at] => 2015-06-24T01:02:00-05:00
[published_scope] => global
[option1_name] => Title
[option1_value] => Default Title,
[image_src] => https://cdn.shopify.com/s/files/1/0154/0015/products/circa.jpg?v=1447768099
)
[ProductVariant] => Array
(
Array
(
[variant_id] => 1096438833
[title] => Default Title
[option1_name] => Default Title
[option2_name] =>
[option3_name] =>
[variant_sku] => E9LT95Q - E1A265Q
[variant_grams] => 0
[variant_inventory_tracker] => shopify
[variant_inventory_qty] => 4
[variant_inventory_policy] => deny
[variant_fulfillment_service] => manual
[variant_price] => 8999.00
[variant_compare_at_price] =>
[variant_requires_shipping] => 1
[variant_taxable] =>
[variant_barcode] =>
[variant_image] => 1151565069
[variant_weight_unit] => kg
)
)
[ProductImage] => Array
(
Array
(
[variant_image_id] => 1225124
[variant_image] => https://cdn.shopify.com/s/files/1/0154/0015/products/2780-ca4_2d26fff2-368d-4271-bd13-c344b5d08fb7.jpg?v=1447768100
)
)
EDIT: Fix Relationships
Replace your Product relationships with the following:
Product.php:
public $hasMany = array(
'ProductVariant' => array(
'className' => 'ProductVariant',
'foreignKey' => 'product_id',
'dependent' => false
),
'ProductImage' => array(
'className' => 'ProductImage',
'foreignKey' => 'product_id',
'dependent' => false
),
'ProductMercadolibre' => array(
'className' => 'ProductMercadolibre',
'foreignKey' => 'product_id',
'dependent' => false
)
);
See
Model::saveAssociated() in Cookbook 2.x | Saving your Data

Related

CakePHP 2.8 saveAll Creates Two Records Instead of One

I'm cloning a milestone record with associated data. I first find the data from the source milestone, then change the contents of the array and remove all 'id' fields. Then I attempt a 'saveAll'. All the associated data is being created properly but the 'milestones' table now has 2 new records instead of 1. The second record contains the ID used by the associated data, so why does the first record even exist?
The Data (simplified) and Call:
$test = array(
'Milestone' => array(
'name' => 'Clone Test',
'customer_status' => '',
'time_to_complete' => '1',
'is_active' => true,
),
'MilestoneAlert' => array(
(int) 0 => array(
'name' => 'Clone Test',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'First alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'type' => 'customer',
'milestone_alert_type_id' => '0',
'email' => null,
'subject' => 'Second alert!',
'message' => 'Add a message',
'recipient_name' => '',
'is_active' => true,
)
),
'MilestoneCondition' => array(
(int) 0 => array(
'name' => 'Clone Test',
'condition' => 'First condition.',
'is_active' => true,
),
(int) 1 => array(
'name' => 'Clone Test 1',
'condition' => 'Second condition.',
'is_active' => true,
)
)
);
$this->loadModel('Milestone');
$this->Milestone->create();
$this->Milestone->saveAll($test);
In Model/Milestone.php:
public $hasMany = array(
'MilestoneAlert' => array(
'className' => 'MilestoneAlert',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'MilestoneCondition' => array(
'className' => 'MilestoneCondition',
'foreignKey' => 'milestone_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => 'MilestoneCondition.order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
In Model/MilestoneAlert.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In Model/MilestoneCondition.php:
public $belongsTo = array(
'Milestone' => array(
'className' => 'Milestone',
'foreignKey' => 'milestone_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
After running the method, there are two records in 'milestone_conditions', two records in 'milestone_alerts', and two identical records in 'milestones'. How do I keep it from creating two 'milestone' records?
Try to get the original data like this:
$test= $this->Milestone->findById('insert your id');
$this->Milestone->create(); // Create a new record
$this->Milestone->saveAll($test,array('deep' => true)); // And save it

Cake PHP HABTM relationship with same model

I have a products table and a products_relateds table. This holds 2 references to products (product_id and related_id)
I'm trying to set up a HABTM relationship for this like so in my Product Model
public $hasAndBelongsToMany = array(
'Related' => array(
'className' => 'Product',
'joinTable' => 'products_relateds',
'foreignKey' => 'product_id',
'associationForeignKey' => 'related_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Does this look right? Do i need to create a Related model?
I get no errors, and viewing the products page will not load when this relationship is in place
That code is fine, your error must be elsewhere. Using $this->Product->findBy(1) should return something like this:
array(
'Product' => array(
'id' => '1',
'name' => 'Test 1'
),
'Related' => array(
0 => array(
'id' => '2',
'name' => 'Test 2',
'ProductsRelated' => array(
'id' => '3',
'product_id' => '1',
'related_id' => '2'
)
),
1 => array(
'id' => '3',
'name' => 'Test 3',
'ProductsRelated' => array(
'id' => '1',
'product_id' => '1',
'related_id' => '3'
)
)
)
)

HABTM Just main model is saved with saveall()

I'm having problems with HABTM + cakephp.
In my app i have this models (with relation definition):
Cliente:
public $hasAndBelongsToMany = array(
'TiposComercio' => array(
'className' => 'TiposComercio',
'joinTable' => 'tipos_comercio_cliente',
'foreignKey' => 'cliente',
'associationForeignKey' => 'tipo_comercio'
)
);
TiposComercio:
public $hasAndBelongsToMany = array(
'Cliente' => array(
'className' => 'Cliente',
'joinTable' => 'tipos_comercio_cliente',
'foreignKey' => 'tipo_comercio',
'associationForeignKey' => 'cliente'
)
);
When the form is posted, i have in array $this->request->data this:
array(
'Cliente' => array(
'password' => '*****',
'razao_social' => 'Teste',
'responsavel' => 'responsavel',
'cidade' => '1',
'cep' => '13560201',
'logradouro' => 'Log test',
'numero' => '',
'bairro' => '',
'complemento' => '',
'atividades' => '',
'username' => 'username11',
'TiposComercio' => array(
(int) 0 => '1',
(int) 1 => '4'
)
)
)
When i execute $this->Cliente->saveAll($this->request->data); in ClientesController I have the following problem:
Just Cliente data is saved. Nothing of TiposComercio is saved.
What's wrong?
Thanks!
The structure of your data array seems to be wrong. Have a look at the manual for saving HABTM data: http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Based on the example, your data array should be formed like this:
array(
'Cliente' => array(
'password' => '*****',
'razao_social' => 'Teste',
'responsavel' => 'responsavel',
'cidade' => '1',
'cep' => '13560201',
'logradouro' => 'Log test',
'numero' => '',
'bairro' => '',
'complemento' => '',
'atividades' => '',
'username' => 'username11',
),
'TiposComecio' => array(
(int) 0 => '1',
(int) 1 => '4'
)
)

CakePHP saving data in HABTM fields

I am using these three relations User, Movie and UsersWatchlist.. Where users_watchlists contains movie_id and user_id as attributes.. I have this structure
array(
'User' => array(
'id' => '3'
),
'UsersWatchlist' => array(
'UsersWatchlist' => array(
(int) 0 => '3'
)
)
)
public function watchlist($id = null) {
$userid = '3';
if (!$id && $userid != 3) {
$this->Session->setFlash('Invalid Movie');
$this->redirect($this->referer(array('action' => 'listing')));
}
$this->request->data['User']['User'][] = $userid;
$this->request->data['Movie']['Movie'][] = $id;
debug($this->request->data);
if ($this->User->saveAll($this->request->data)) {
debug("saved");
$this->Session->setFlash('The movie has been added to your watchlist', 'admin/flash_success');
//$this->redirect($this->referer(array('action' => 'listing')));
} else {
debug("saved bo");
$this->Session->setFlash('The movie could not be added to your watchlist. Please, try again.', 'admin/flash_error');
//$this->redirect($this->referer(array('action' => 'listing')));
}
}
I used saveAll method on User but its not saving.. Please provide me solution to save the data..
In Movie model,
public $hasAndBelongsToMany = array('User' => array(
'className' => 'User',
'joinTable' => 'users_watchlists',
'foreignKey' => 'movie_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In User model,
public $hasAndBelongsToMany = array(
'Movie' => array(
'className' => 'Movie',
'joinTable' => 'users_watchlists',
'foreignKey' => 'user_id',
'associationForeignKey' => 'movie_id',
'unique' => 'keepExisting',
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
In UsersWatchlist model,
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Movie' => array(
'className' => 'Movie',
'foreignKey' => 'movie_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
The data array you're trying to save is wrong.
If you're saving throung the User model your structure should be:
array(
'User' => array(
'id' => '3'
),
'Movie' => array(
'Movie' => array(
(int) 0 => '3'
)
)

CakePHP display custom fields from array

I know the title doesn't describe the best what I want to achieve, but I couldn't think of anything else.
Let's say I have the following array:
[Sender] => Array
(
[0] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 1
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 3
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
[1] => Array
(
[id] => 1
[username] => admin
[PrivateMessagesUser] => Array
(
[id] => 3
[private_message_id] => 1
[sender_id] => 1
[recipient_id] => 2
[sender_status] => 1
[recipient_status] => 0
[random_key] =>
)
)
)
I am using the ContainableBehaviour to cut off extra data.
My problem is: how do I filter out the Senders after a key which is present in PrivateMessagesUser? Say I need only the Sender where PrivateMessagesUser.recipient_id = 3.
I tried with
'Sender' => array(
'PrivateMessagesUser' => array(
)
),
but it didn't work. Looks like I have to get over the [0], [1]... keys somehow and I don't know how.
Any help would be appreciated!
EDIT
Here's how I obtain the array posted above:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()
),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
'PrivateMessagesUser' => array(
'fields' => array('PrivateMessagesUser.id')
//'conditions' => array('PrivateMessagesUser.recipient_id' => $this->Auth->user('id'))
)
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
);
How can I edit these lines in order to achieve the desired result?
EDIT 2
I am calling the paginate() from the PrivateMessagesController.
Associations:
User Model:
var $hasAndBelongsToMany = array(
'PrivateMessageSent' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'sender_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'PrivateMessageReceived' => array(
'className' => 'PrivateMessage',
'joinTable' => 'private_messages_users',
'foreignKey' => 'recipient_id',
'associationForeignKey' => 'private_message_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
PrivateMessage Model:
var $hasAndBelongsToMany = array(
'Sender' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'sender_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Recipient' => array(
'className' => 'User',
'joinTable' => 'private_messages_users',
'foreignKey' => 'private_message_id',
'associationForeignKey' => 'recipient_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
);
PrivateMessagesUser Model:
var $belongsTo = array(
'PrivateMessage' => array(
'className' => 'PrivateMessage',
'foreignKey' => 'private_message_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Sender' => array(
'className' => 'User',
'foreignKey' => 'sender_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
And the database tables look like:
users: id, username, ...
private_messages: id, subject, ...
private_messages_users: id, private_message_id, sender_id, recipient_id, status, ...
There are three ways to achieve this.
Looking at your returned data array, I'm guessing PrivateMessagesUser belongsTo Sender.
1. Querying the PrivateMessagesUser model
Sometimes, all it takes is querying the right model. You can apply the conditions directly to the model you want to apply your restrictions on.
$this->Sender->PrivateMessagesUser->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender')
));
2. Applying conditions to related models
This doesn't work all the time, because CakePHP's SQL generation doesn't always work the way you want it to. But in simple cases like a hasMany relationship, you can use this:
$this->Sender->find('all', array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('PrivateMessagesUser')
));
Again, this will work only if Cake executes a JOIN for the Containable parameters AND uses the conditions right.
3. Using joins
This method is foolproof but a little messy since it's highly customizable.
$this->Sender->find('all', array(
'joins' => array(
array(
'table' => 'private_messages_users',
'alias' => 'PrivateMessagesUser',
'type' => 'inner',
'conditions' => array(
'PrivateMessagesUser.sender_id = Sender.id',
'PrivateMessagesUser.recipient_id' => 3
)
)
)
));
My last piece of advice for you is to place this code into the Model. Follow the principle of "fat models, skinny controllers" whenever possible.
In the Sender model:
function fetchByRecipientId($recipientId) {
...
}
Good luck!
EDIT: In order to make this work for pagination, follow the methods above but use the following format:
$this->paginate = array(
'PrivateMessagesUser' => array(
'conditions' => array('PrivateMessagesUser.recipient_id' => 3),
'contain' => array('Sender'),
// 'order' => ... other keys if you wish
)
);
$this->set('senders', $this->paginate());
You can put conditions inside Containable, like so:
$this->Sender->find('all', array(
'contain' => array(
'PrivateMessagesUser' => array('conditions' => array('recipient_id' => 3))
)
));
EDIT:
Try modifying your $this->paginate as follow:
$this->paginate = array(
'conditions' => array(
'PrivateMessage.id' => $this->__getUserPrivateMessagesInbox()//array of message id's
),
'fields' => array('PrivateMessagesUser.id'),
'contain' => array(
'Sender' => array(
'fields' => array('id', 'username'),
),
'Recipient' => array(
'fields' => array('id', 'username'),
'conditions' => array('Recipient.id' => $this->Auth->user('id'))
)
)
)
Then call your paginate $this->paginate($this->PrivateMessage)

Resources