CakePHP: Using attributesof model in associations-condition - cakephp

I have a table that has a "hasOne"-association to another table, but without any foreign key. So my "hasOne"-association finds the related entity with a customized finder-method:
$this->hasOne('HourlyRates', [
'foreignKey' => false,
'finder' => ['byShift' => ['userId' => '1', 'shiftBegin' => '2016-01-01']]
]);
My problem is, that the options for the finder have to be the attributes of the actual entity of the first table. This is the user_id of one entity and the shift-begin of one entity.
I tried
'finder' => ['byShift' => ['userId' => 'Shifts.user_id', 'shiftBegin' => 'Shifts.begin']]
But it didn't work.
So do you know, how to access the attributes of one entity in the Table-class?

Related

How to add link to show action of the relation entity on relation field in SonataAdminBundle

Im making admin panel in SonataAdminBundle.
In User show action i have field companies which return array of companies assigned to the user.
It is a OneToMany relation. UserCompany has user_id and company_id.
I want to create link on each returned company name, which points to it's entity show action.
This is code from configureShowFields() function in UserAdmin class:
->with('Assigned organizers',['class' => 'col-md-6'])
->add('companies', null, [
'label' => 'Organizers',
])
->end()
I managed to create a link on a string field pointing to show action of an entity, but the id property is taken from the current entity view:
->with('Address', ['class' => 'col-md-6'])
->add('userProfile.locality', 'url', [
'route' => [
'name' => 'admin_app_employee_show',
'identifier_parameter_name' => 'id'
],
'label' => 'Localiy',
])
What's more Sonata Admin create links on related fields, when the relation is direct,
for example:
Company has many Employee. Then in Company show action on employees field
I see array with links already heading to edit action of Employee entty.
Maybe there is a possibility to override template for this field, but it seems unclear for me,
as the documentation lacks of more advanced examples.
This is how I tried to test overriding the template of a field:
->add('userProfile.street', null, array(
'label' => 'Street',
'template' => 'custom-field.html.twig',
))
Location of the template: App/templates/Admin/
Any help appreciated
SonataAdmin automatically creates links to related entities once it has all of them configured and added to services.
Then you can just change the route action of the link on the relation field as following:
->with('Assigned events', ['class' => 'col-md-6'])
->add('events', null, [
'route' => [
'name' => 'show'
],
'label' => 'Events',
])
->end()
You can also change the type of relation field eg.'many_to_one' instead of null which might help in some cases.

Two users associated to one transaction in CakePHP 3.x

In my app there is a Transaction table with:
seller_id, buyer_id and asset_id.
seller_id and buyer_id are id's supposed to point to Users table. To stick to the convention and keep automatic associations both should be called "user_id" (which is of course impossible)
What is the correct way to create such associations in CakePHP 3.x?
My guess is that I should create special association tables:
Sellers (id, user_id)
Buyers (id, user_id)
and then associations would be trough those tables:
Transaction => Sellers, Buyers => Users
Is that correct? Would it work? Is there a better way?
You can define the relationship with different alias and foreign keys like below.
In your transactions model/Table.
$this->belongsTo('Sellers' , [
'foreignKey' => 'seller_id',
'className' => 'Users'
]);
$this->belongsTo('Buyers' , [
'foreignKey' => 'buyer_id',
'className' => 'Users'
]);
If you also want to define the relationaship in user model, you can define this in this way.
In User model/table
$this->hasMany('BuyerTransactions' , [
'foreignKey' => 'buyer_id',
'className' => 'Transactions'
]);
$this->hasMany('SellerTransactions' , [
'foreignKey' => 'seller_id',
'className' => 'Transactions'
]);

Saving / Creating data to associated table is not working

I have three table,
Authors
Stories
Details
Stories and Details are associated with the Authors, with hasOne relationship.
Bellow is the code in my AuthorsController
function add(){
if($this->request->is('POST')){
$author = $this->Authors->newEntity($this->request->data,
['associated' => ['Stories', 'Details'], 'validate' => false]
);
$this->Authors->save($author);
}
}
This is only saving data in the Authors table, not in the other two table.
Bellow is the data I have in $this->request->data
'Authors' => [
'name' => 'Bikash'
'Age' => '22'
'stories' => [
'name' => 'Life Without the L'
'gener_id' => 5
]
'details' => [
'qualification' => 'XYZ'
'biography'
]
];
What I am missing?
You are using the wrong property names, stories and details won't work.
The default association property name for hasOne associations, is the underscored singular variant of the association alias, so for Stories that would story, and for Details it would be detail.
See also
Cookbook > Database Access & ORM > Associations - Linking Tables Together > HasOne Associations
Inflector Sandbox > Stories
Inflector Sandbox > Details

The requested URL /drupalhr/drupal/employee/add/ was not found on this server

I have created a custom module in drupal with entities. I have installed the entity api module. I have created my database schema with just two columns (employee_id, first_name) through the help of employee_management.install file (where as employee_management is my custom module name) and employee is my entity name.
I have also written the requisite functions employee_management.module but still it shows me the error , Whenever i tried to add a new entity in the admin/structure/employee it shows me the following error: "Not Found".
The requested URL drupal/employee/add/ was not found on this server.
function employee_management_entity_info() {
$employee_info['employee'] = array(
// A human readable label to identify our entity.
'label' => t('Employee Entity'),
// The controller for our Entity - extends the Drupal core controller.
'controller class' => 'EmployeeController',
// The table defined in hook_schema()
'base table' => 'employee',
// Returns the uri elements of an entity
'uri callback' => 'employee',
// Fieldable that we can attach fields to it - the core functionality will
// do the heavy lifting here.
'fieldable' => TRUE,
// The unique key of our base table.
'entity keys' => array(
'id' => 'employee_id',
),
// FALSE disables caching - caching functionality is handled by Drupal core
'static cache' => TRUE,
// Attach bundles - i.e. alternative configurations of fields associated with a main entity.
'bundles' => array(
'employee' => array(
'label' => 'Employee',
// Information below is used by the Field UI - they "attach" themselves here and lets us
// do the standard field management that all the core entities enjoy.
'admin' => array(
'path' => 'admin/structure/employee/add',
'access arguments' => array('administer employee entities'),
),
),
),
// View modes allow entities to be displayed differently based on context. We simply have one option
// here but an alternative would be to have a Full and Teaser mode akin to node.
'view modes' => array(
'full' => array(
'label' => t('Full'),
'custom settings' => FALSE,
),
)
);
return $employee_info;
}
EDIT
function employee_uri($employee) {
return array(
'path' => 'employee/' . $employee->employee_id,
);
}
And here is the complete list of function in the file employee_management.module
You don't automagically get the route and form to create your entity, you'll have to implement that yourself. See hook_menu and this guide.

CakePHP using saveAll: How do I save extra data with the HABTM link record?

I have been able to use CakePHP's saveAll method to simultaneously create 'Members' and enroll them in an 'Event' (creating the HABTM link record), which is awesome. For example, this code creates two new 'Members' and adds a record for each of them to the 'EventsMember' table, enrolling them 'Event' 10:
$data = array(
'0' => array(
'Member' => array('email' => 'nobody#nowhere.com'),
'Event' => array('id' => 10)
),
'1' => array(
'Member' => array('email' => 'somebody#nowhere.com'),
'Event' => array('id' => 10)
)
);
$this->Member->saveAll($data);
However, the record in the 'EventsMember' table also has a field called 'role' that holds something like "Presenter" or "Host" or "Attendee" and I would like to save that data when I create the relationship. I tried this and it does not work (the 'EventsMember' 'role' field is always blank):
$data = array(
'0' => array(
'Member' => array('email' => 'nobody#nowhere.com'),
'Event' => array('id' => 10),
'EventsMember' => array('role' => 'Host')
),
'1' => array(
'Member' => array('email' => 'somebody#nowhere.com'),
'Event' => array('id' => 10),
'EventsMember' => array('role' => 'Attendee')
)
);
$this->Member->saveAll($data);
I'm wondering if this is even possible, and if maybe I have to use some kind of callback like beforeSave or afterSave to get this done? I've read that there are some problems with these callbacks when using saveAll, so I'm looking for any tips on what would be the best practice here.
Thanks!
EDIT: I took Adam's advice and made the following changes to my models:
// Event.php
var $hasMany = array('EventsMember');
// Member.php
var $hasMany = array('EventsMember');
// EventsMember.php
var $belongsTo = array('Event', 'Member');
Then in my controller, my code looked almost identical to my second example, except I called the saveAll() method from the EventsMember model, as described in the documentation:
$data = array(
'0' => array(
'Member' => array('email' => 'nobody#nowhere.com'),
'Event' => array('id' => 10),
'EventsMember' => array('role' => 'Host')
),
'1' => array(
'Member' => array('email' => 'somebody#nowhere.com'),
'Event' => array('id' => 10),
'EventsMember' => array('role' => 'Attendee')
)
);
$this->EventsMember->saveAll($data);
The result was no Member or EventsMember records were saved at all. I tried triggering the save from the Member model ($this->Member->saveAll($data);) and this saved the Member records, but not the joining EventsMember records.
I tried removing the pre-existing HABTM associations, and it made no difference. The beforeSave method of the EventsMember model is getting triggered when I call $this->EventsMember->saveAll($data); but it looks like it won't actually save anything.
I'm stymied.
UPDATE: It turns out that no records were created because the joining records were all being created with Event ids and Member ids of 0, which goes against a unique key I have on those two fields combined (that is, no Member can enroll in an Event twice).
Does this suggest that the join model saveAll functionality is not working as documented, since the Member record isn't getting created (meaning there is no Member id to use in the joining record), and the existing Event id is not being passed to the joining EventsMember record either?
VERDICT: I changed the controller to loop on each record and attempt to $this->EventsMember->saveAll($data) for each index of the array, instead of passing the entire array at once. It worked, but was significantly slower than my first example (at the very top). Mind you, I am using transactions, so perhaps using the atomic => false; option would speed things up, while still allowing me to recover from any invalid records.
Bottom line, if you need to save extra data in join table records, you have to process them one at a time. If not, use the method at the top for the best performance.
You can use The Join Model in this case.

Resources