cakephp testing suite: import fixtures tables for HABTM - testing

I have a model Post -> hasAndBelongsToMany -> Tag
For testing, I created the fixtures for each model, for example, a fixture for the model Post looks like this
class PostFixture extends CakeTestFixture {
var $import = array('model' => 'Post', 'records' => true, 'connection' => 'fixtures');
}
And everything works great for that Model, but when I try to create the fixture for the HABTM relationship, using the same approach doesn’t work:
class PostsTagFixture extends CakeTestFixture {
var $import = array('model' => 'PostTag', 'records' => true, 'connection' => 'fixtures');
}
The SQL generated by CakePHP is the following
CREATE TABLE `service_types_technicals` (
`technical_id` int(20) NOT NULL AUTO_INCREMENT,
`service_type_id` int(20) NOT NULL AUTO_INCREMENT,
`id` varchar(255) NOT NULL, PRIMARY KEY (`id`)) ;
Wich is not correct because the table does not have a field named id.
Then, I tried this:
class PostsTagFixture extends CakeTestFixture {
var $name = 'PostsTag';
var $import = array('table' => 'posts_tags', 'records' => true, 'connection' => 'fixtures');
}
And again, error, but this time the SQL was:
CREATE TABLE `service_types_technicals` (
`technical_id` int(20) NOT NULL AUTO_INCREMENT,
`service_type_id` int(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`service_type_id`)) ;
What am I doing wrong? What is the correct way to import fixtures from another database for has and belongs to many relationships?
Thank you!

Mauro Zadunaisky,
as you state that service_types_technicals does not have an id field, I guess that CakePHP automatically deduces a HABTM from service_types to technicals, as both are nouns written in plural (CakePHP convention). If this is not what you had in mind, then you are forced to alter the name of the table to stay within the conventions.

The problem was the missing of the field id in the habtm relation table, it's fixed now

Related

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'email' cannot be null [LARAVEL]

I don't know what is wrong my code,please help I am almost finish it. I am using Laravel 7 btw
I received this message when I wanna update the phone number/email/password
Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'email' cannot be null (SQL:
update `users` set `email` = ?, `password` =
$2y$10$KZBGY4BFJIWzgh2wGhQ3yuZivuzo..MOLs2ahAYbXpecOUZsZ/nvC, `users`.`updated_at` = 2022-01-26
21:46:50 where `id` = 7)
Here is my update function
public function updateStaffDetails(Request $request, Staff $staff, User $user)
{
//$name = $request->input('stud_name');
$staff->update([
'staffPhone' => $request['staffPhone'],
'staffEmail' => $request['staffEmail'],
'staffPassword' => $request['staffPassword'],
]);
$user =Auth::user();
$user->update([
//'name' => $staff->staffName,
'email' => $staff->staffEmail,
'password'=> Hash::make($staff->staffPassword), //bcrypt($staff->staffPassword)
]);
$staff->user_id = $user->id;
$user->save();
$staff->save();
return redirect()->route('home',Auth::user())
->with('success','Staff details updated successfully.');
}
as you can see the Staff table will be copied to the users table once it is updated but the email from Users table is null...
here is my routes (because I think the problem is my route but i am not sure )
//admin show details
Route::get('/showDetailsAdm', 'StaffController#showDetailsAdm')->name('admins.showDetailsAdm');
//admin update
Route::put('/admins/updateStaffDetails', 'StaffController#updateStaffDetails')->name('admins.updateStaffDetails');
here is the picture of the column Staffs and Users user_id is FK from Users table
tables
Your route must be like
Route::put('users/{user}/staffs/{staff}/update','StaffController#updateStaffDetails')->name('admins.updateStaffDetails');
Then you can get $user and $staff in your controller. Now, $staff isn't null so you can get email from it.
While calling to this route you need to pass user_id and staff_id as shown below:
route('admins.updateStaffDetails', [$user_id, $staff_id] )

Left Join CakePHP3

I'm trying to do a LEFT JOIN in CakePHP3.
But all I get is a "is not associated"-Error.
I've two tables BORROWERS and IDENTITIES.
In SQL this is what I want:
SELECT
identities.id
FROM
identities
LEFT JOIN borrowers ON borrowers.id = identities.id
WHERE
borrowers.id IS NULL;
I guess this is what I need:
$var = $identities->find()->select(['identities.id'])->leftJoinWith('Borrowers',
function ($q) {
return $q->where(['borrowers.id' => 'identities.id']);
});
But I'm getting "Identities is not associated with Borrowers".
I also added this to my Identities Table:
$this->belongsTo('Borrowers', [
'foreignKey' => 'id'
]);
What else do I need?
Thanx!
The foreign key cannot just be 'id', that's not a correct model association. You'd need to put a 'borrower_id' field in identities, and declare it like this in the Identities model:
class Identities extends AppModel {
var $name = 'Identities';
public $belongsTo = array(
'Borrower' => array (
'className' => 'Borrower',
'foreignKey' => 'borrower_id'
)
);
Note the capitalization and singular/plural general naming conventions which your example doesn't follow in the least - ignoring those will get you some really hard to debug errors..
Yup. It was an instance of \Cake\ORM\Table, due to my not well chosen table name (Identity/Identities). I guess it's always better not to choose those obstacles, for now I renamed it to Label/Labels.
This query now works perfectly:
$var = $identities
->find('list')
->select(['labels.id'])
->from('labels')
->leftJoinWith('Borrowers')
->where(function ($q) {
return $q->isNull('borrowers.id');
});

Yii order by another table with has_many relation

I have this Object model with 'has_many' relation to Variables
public function relations()
{
return array(
'variables' => array(self::HAS_MANY, 'Variables', 'variable_id')
);
}
Now i want to use the variables to order my data like
$criteria->with = array('variables');
$criteria->order = 'variables.id DESC';
But it doesn't work.
Is there a way to do something like this? Thanks.
You can define the relation directly with an order if you want, in this case you can do.
public function relations()
{
return array(
'variables' => array(self::HAS_MANY, 'Variables', 'object_id', 'order'=>'variables.id DESC')
);
}
What you wrote it is not working because you have a 1 to many relation. The criteria will run 2 queries, 1 to get the main record, the second time to get the relations. That is why your order is not working.
If you want it to work like you said you should do a ->join instead of ->with.
There is quite a difference between the 2 so take care how you are writing the criteria.
I think the issue is with foreign key binding, if you are adding a relationship in object table (Object model) which has many variables having object_id as foreign key in variable table (Variable model) then you need to define relationship as follows:
public function relations()
{
return array(
'variables' => array(self::HAS_MANY, 'Variables', 'object_id') // check the change in foreign key column
);
}

CakePHP vs Rails howto retrieve data from related table

I am new in CakePHP, but I use Rails. I would like to do something like this in CakePHP:
class Manager < ActiveRecord::Base
has_many :employees
end
and ask then the object like this:
m = Manager.find(1)
# Sends SQL query SELECT COUNT * FROM EMPLOYEES WHERE MANAGER_ID = 1
count = m.employees.count
# Sends SQL query SELECT * FROM EMPLOYEES WHERE MANAGER_ID = 1
m.employees.each do |e|
puts e.name
end
I have this code in CakePHP...
class Manager extends AppModel {
public $hasMany = array(
'Employee' => array(
'className' => 'Employee',
'order' => 'Employee.created DESC'
)
);
}
class Employee extends AppModel {
public $belongsTo = 'Manager';
}
How can I do implementation of these (above) functionality (which is in RoR easy made by its ORM) in CakePHP?
Thanks for help...
Myth Rush
Your question boils down to "How can I retrieve the Manager with id=1 and find his Employees.
In CakePHP you would issue the following find query to retrieve the desired manager entry:
$manager = $this->Manager->findById(1);
// or
$manager = $this->Manager->find('first', array(
'conditions' => array(
'Manager.id' => 1
)
);
The above find calls fetch the manager with id=1 from the database and because you set up the relationship Manager hasMany Employee, the result will also contain all employees for the manager ordered by Employee.created DESC.
The resultset would look something like this:
Array
(
[Manager] => Array
(
[id] => 1
[field1] => value1
)
[Employee] => Array
(
[0] => Array
(
[id] => 2
[manager_id] => 1
[name] => Bar
)
[1] => Array
(
[id] => 1
[manager_id] => 1
[name] => Foo
)
)
)
As you can see, CakePHP uses an array format for returned results and not an object as in Ruby on Rails. Therefore you have to access your related data within the resulting array.
Another important difference between CakePHP and Ruby on Rails(RoR) is, that in CakePHP the queries to the db are executed the moment you call them, whereas in RoR they are lazily executed the moment you try to access the results.
To complement your RoR example for accessing employees here is the CakePHP version:
$employee_count = count($manager['Employee']);
foreach ($manager['Employee'] as $e) {
echo $e['name'];
}
I hope this clears up some confusion.
I think you are looking for the containable behavior of CakePHP.
It is important to attach the containable behavior to your model(s), otherwise it won't work.

Fluent NHibernate Parent-child cascade SaveOrUpdate fails

I have a parent-child relationship that I've put a test case together between Users and Groups. I did this to replicate a failure in
a Parent-Child relationship when trying to perform a cacade insert using thes relationship.
The two SQL tables are as follows:
CREATE TABLE [dbo].[User]
(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] [varchar](50) NOT NULL,
)
CREATE TABLE [dbo].[Group]
(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[GroupName] [varchar](50) NOT NULL,
[UserId] [int] NOT NULL,
)
ALTER TABLE [dbo].[Group] WITH CHECK ADD CONSTRAINT [FK_Group_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([Id])
The objects represent these two tables with the following mappings:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("[User]");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name).Not.Nullable();
HasMany(x => x.Groups).KeyColumn("UserId").Cascade.SaveUpdate();
}
}
public class GroupMap : ClassMap<Group>
{
public GroupMap()
{
Table("[Group]");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.GroupName).Not.Nullable();
References(x => x.User).Column("UserId").Not.Nullable();
}
}
The code to created the objects is simply:
User u = new User() { Name = "test" };
Group g = new Group() { GroupName = "Test Group" };
u.Groups.Add(g);
using (var session = factory.OpenSession())
{
session.SaveOrUpdate(u);
}
However it fails with exception "Cannot insert the value NULL into column 'UserId', table 'test.dbo.Group'; column does not allow nulls. INSERT fails.
The statement has been terminated". I suspect that this is dude to the parent object's Id (an identity column) being passed through as NULL and not the new values. Is this a bug or is there a way to fix these mappings so that this cascade relationship succeeds?
I recently had this exact type of mapping working fine in a project. My advice is:
Learn how the Inverse attribute of a HasMany relationship works. Great explanation here
You need a two way association between the parent and child object. This is explained at the bottom of the article linked to above.
Another good advice is to encapsulate your collections better
- Don't access your collections modification methods directly. The collection properties should be read-only and the parent (User class in your case) should have AddGroup() and RemoveGroup() methods that changes the private collection. In order for this to work you have to let NHibernate access the private collection member by using the .Access.CamelCaseField(Prefix.Underscore) or similar mapping attribute. Good discussion about it here
I can post an example mapping and class files if needed.
You will have to save the user first then assign the group to the user and save that:
using (var session = factory.OpenSession())
{
User u = new User() { Name = "test"};
session.SaveOrUpdate(u);
Group g = new Group() { GroupName = "Test Group", User = u };
session.SaveOrUpdate(g)
}
I have found that you cannot cascade save child /parent related objects which have only just been created.