Can't solve child parent association in cakephp 3 - php

I have table with a parent child relationship with itself:
mysql> desc features;
+---------------------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| featureID | varchar(45) | NO | | NULL | |
| probeID | int(11) | YES | | NULL | |
| shortName | varchar(45) | NO | | NA | |
| start | int(11) | NO | | NULL | |
| stop | int(11) | NO | | NULL | |
| strand | int(11) | NO | | NULL | |
| curatedManually | varchar(45) | NO | | NA | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
| descriptions_id | int(11) | YES | MUL | NULL | |
| features_types_id | int(11) | NO | MUL | NULL | |
| chromosomes_id | int(11) | NO | MUL | NULL | |
| species_id | int(11) | NO | MUL | NULL | |
| strains_id | int(11) | NO | MUL | NULL | |
| parents_features_id | int(11) | YES | MUL | NULL | |
+---------------------+-------------+------+-----+-------------------+----------------+
The according fields are parents_features_id and id, because a feature can have "child"-features or "parent"-features. There is a foreign key relationship established with this fields.
KEY `fk_features_Features1_idx` (`parents_features_id`),
CONSTRAINT `fk_features_Features1` FOREIGN KEY (`parents_features_id`) REFERENCES `features` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
I used "cake bake all features" to create all necessary models, controllers etc.
When I open the features page I only get the error message "Features is not associated with ParentsFeatures"
I tried to solve it by exchanging the automatic original code
$this->belongsTo('Features', [
'foreignKey' => 'parents_features_id'
in Model/Table/FeaturesTable.php for this relationship by the following code:
$this->belongsTo('ParentsFeatures', [
'className' => 'Features',
'foreignKey' => 'parents_features_id'
]);
$this->hasMany('ChildFeatures', [
'className' => 'Features',
'foreignKey' => 'parents_features_id'
But than I get the error message "Features is not associated with Features"
I am a little bit stuck here and would really appreciate any help to solve this.
all the best
Nadine

Making changes to the associations in your table will not change the way the baked controllers will query the data, you'll have to change them too, or re-bake your code.
However, this will never bake correctly unless you start following the conventions, that is name the foreign key column parent_id, only then bake will be able to create the proper associations (which will be named ParentFeatures and ChildFeatures), and while you're at it, consider changing the other column names too (lowercase underscored).
That being said, there might be a bug that occours somewhere between renaming indexes, creating and deleting foreign key constraints, etc (can't pinpoint it down), which then causes wrong association names used for contain in the find() calls of the controller actions, ie bake will generate something like
'contain' => ['Features']
instead of
'contain' => ['ParentFeatures']
which it used for the association in the baked table class.
However I'm not being able to reproduce it reliably right now. In case this is what you are experiencing, you might want to report this as an issue over at GitHub.
In case re-baking doesn't fix it, manually check the find() calls in your controller actions and change the contained association to ParentFeatures.

Related

Mysql speed: table with many columns or 2 tables using a join

I tried searching for this but I could not find anything about this but design choices.
So my question is like the title. What is faster? Create 1 table with many columns or create 2 or 3 (for many to many) tables with join(s).
I like the idea of have multiple tables so the data is separated. Mostly for many to many like data. But my friend told me having 5 columns with boolean is just fine. But I like the idea of have a table with the settings and then a table between with user.id and setting.id. But my question is also, does it have a impact on the query?
example:
Users
- id
- Email
- SettingA
- SettingB
- SettingC
OR example:
Uers
- id
- email
Users_Settings
- user_id
- setting_id
Settings
- id
- someSettingsValue
What woult be faster for Mysql to query the data? (retrieving settings for user)
not at all.. Only joins between 2 r 3 will take time compared to single table fields.
It's not about preferring single table with many columns or preferring multiple tables. It's about Normalization.
According to your provided schema, if all users will always have three settings, i.e. Setting A, B and C, then it's better to create single table with these three columns for settings.
users table:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Email | varchar(128) | NO | | NULL | |
| SettingA | tinyint(1) | NO | | NULL | |
| SettingB | tinyint(1) | NO | | NULL | |
| SettingC | tinyint(1) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
But if any of the setting is saved is null, then better is to create separate table for settings and then a pivot table for maintaining users' settings without primary key.
users table:
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Email | varchar(128) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
settings table:
+---------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| setting_value | tinyint(1) | NO | | NULL | |
+---------------+------------+------+-----+---------+----------------+
setting_user pivot table:
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| setting_id | int(11) | NO | | NULL | |
| user_id | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+-------+
Where setting_user is the pivot table.
One more thing is considered when creating schema, that, will there be always three settings, or will there be more in future, when application is expanded!

Data migration into CiviCRM - keep legacy IDs

I develop custom migration code using CiviCRM's PHP API calls like:
<?php
$result = civicrm_api3('Contact', 'create', array(
'sequential' => 1,
'contact_type' => "Household",
'nick_name' => "boo",
'first_name' => "moo",
));
There's a need to keep original IDs, but specifying 'id' or 'contact_id' above does not work. It either does not create the contact or updates an existing one.
The ID is auto-incremented, for sure, but MySQL supports to insert arbitrary, unique values in that case.
How would you proceed? Hack CiviCRM to somehow pass the id to MySQL at the INSERT statement? Somehow dump the SQL after the import and manipulate the IDs in-place at the .sql textfile (hard to maintain integrity)? Any suggestions for that?
I have ~300.000 entries at least to deal with, so a fully automated and robust solution is a must. Any SQL magic potentially to do that?
For those who are not familiar with CiviCRM, the table structure is the following:
mysql> desc civicrm_contact;
+--------------------------------+------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------------+------------------+------+-----+-------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| contact_type | varchar(64) | YES | MUL | NULL | |
| contact_sub_type | varchar(255) | YES | MUL | NULL | |
| do_not_email | tinyint(4) | YES | | 0 | |
| do_not_phone | tinyint(4) | YES | | 0 | |
| do_not_mail | tinyint(4) | YES | | 0 | |
| do_not_sms | tinyint(4) | YES | | 0 | |
| do_not_trade | tinyint(4) | YES | | 0 | |
| is_opt_out | tinyint(4) | NO | | 0 | |
| legal_identifier | varchar(32) | YES | | NULL | |
| external_identifier | varchar(64) | YES | UNI | NULL | |
and we talk about the first field.
You should use the external_identifier field which is exactly done for what you want.
This field is not used by CiviCRM itself so there is no risk to mess with core functionality. It's done to link with an external system (legacy for example).
CiviCRM consider the external_identifier to be unique so it will throw an error (using API - I think) or update (using CiviCRM contact import screen) if you try to insert a contact with the same external_identifier.

Laravel 5 custom database sessions?

I'm new to Laravel (using 5.1). I have my entire DB schema (MySQL 5.5) diagrammed and have begin implementing it. The problem is, I need to adapt Laravel to use my sessions table. After making a new migration to bring the table more in line with what Laravel expects, I have this table:
+---------------+---------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------------------------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| id_hash | varchar(255) | NO | UNI | NULL | |
| user_id | bigint(20) unsigned | NO | | 0 | |
| created_at | int(10) unsigned | NO | | 0 | |
| updated_at | int(10) unsigned | NO | | 0 | |
| expires_at | int(10) unsigned | NO | | 0 | |
| last_activity | int(10) unsigned | NO | | 0 | |
| platform | enum('d','p','t','b','a','i','w','k') | NO | | d | |
| ip_address | varchar(40) | NO | | 0.0.0.0 | |
| payload | text | NO | | NULL | |
| user_agent | text | NO | | NULL | |
+---------------+---------------------------------------+------+-----+---------+----------------+
The main thing I need to accomplish is to have id as an auto-incrementing integer (because my Session model has relationships to other models) and use id_hash as the publicly identifying string (I also plan to cut id_hash back to 64), which I think is the token in the payload.
At session creation, id_hash, platform, ip_address, and user_agent will be set, never to change again. After authentication, user_id will be populated, then cleared at logout.
I'm ok with keeping the payload handling as-is.
Is this just a matter of creating a custom class that implements SessionHandlerInterface? What else needs to be in it for handling my extra fields that's not obvious from the session docs?

$mysqli query fails, foreign key constraint fails

This insert command fails:
INSERT INTO posts (id, headline, content, post_date, blog) VALUES (default, 'Birds
in Nepal are being Messed With', 'Have you heard about this? There are birds in
the country of Nepal that are sitting around minding their own business, when out
of nowhere they are getting messed with. Messed with!', curdate(), 'cost');
It dies with this error message:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint
fails (`allanwebdev`.`posts`, CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`blog`)
REFERENCES `blogs` (`blog`))
There are two tables, one called 'blogs' and one called 'posts'.
'blogs' has one column called 'blog' which serves as a primary key:
DESCRIBE BLOGS;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| blog | varchar(10) | NO | PRI | | |
+-------+-------------+------+-----+---------+-------+
SELECT * FROM BLOGS;
+----------+
| blog |
+----------+
| code |
| politics |
| satire |
+----------+
'posts' has a foreign key column called 'blog' which references the primary key in 'blogs'.
DESCRIBE POSTS;
+-----------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| headline | varchar(60) | YES | | NULL | |
| post_date | date | YES | | NULL | |
| content | varchar(64000) | YES | | NULL | |
| blog | varchar(10) | YES | MUL | NULL | |
+-----------+----------------+------+-----+---------+----------------+
What. The heck. Am I doing wrong? Many thanks. This error message does exist elsewhere but invariably they are more complex problems. I'm operating simply and directly from a mysql command line.
Note that the sql call is being made from a php mqsqli object $db->query($sql). The actual string doesn't include a semi-colon at the end.

Cannot add or update a child row: a foreign key constraint fails(Foreign key issue in mysql)

I am getting this error whenever I try to Insert Data into my "Student" table.
Below are the two tables, I am using MySql :
student table:
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+-------------------+----------------+
| S_id | int(20) | NO | PRI | NULL | auto_increment |
| U_id | int(11) | YES | MUL | NULL | |
| sname | varchar(20) | YES | | NULL | |
| gender | varchar(20) | YES | | NULL | |
| email | varchar(320) | YES | UNI | NULL | |
| Phone_Number | int(20) | YES | | NULL | |
user table:
Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+-------------------+----------------+
| U_id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| password | varchar(20) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
When I try to run this query ,
INSERT INTO student(U_id,sname,gender,email,Phone_Number) VALUES ('$U_id','$sname','$gender','$email','$Phone_Number');
I am getting this error:
Cannot add or update a child row: a foreign key constraint fails (`Learn`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`U_id`) REFERENCES `user` (`U_id`))
I tried to look for the solution but most of them are saying keep a common Engine like InnoDB on both the tables but in my table its already defined.I have even followed the steps given here https://stackoverflow.com/a/9139206/2545197
but nothing worked for me.
I made an SQL Fiddle and everything works perferctly.
The only way I can reproduce the error is when a row is inserted into student before the corresponding row in user exists. Can you please double check that this is really true for each inserted row.
Also, you should var_dump() your PHP variables used for the INSERT and check if the problem lies there. IMHO, it can only have to do with a non-existing record in the user table.

Categories