I have 3 tables artist, catalog & cat_artist (pivot table). When retrieving a row from my catalog table I want to get all the associated artists with it. I could just do this with raw sql but since using laravel it feels wrong because it has many of the functions to do this already. So I have a the function in my product model (product modal references the catalog table) to create the join
public function artists()
{
return $this->belongsToMany('App\Artist', 'cat_artist', 'LOOK_UP_TO_CAT_ID', 'LOOK_UP_TO_ARTIST_ID');
}
I then call this before I return my view which gives me the the row from my catalog table
$product = Product::find($id);
Now I want to get all the artists that may belong to this product aswell so I call the following
$artists = $product->artists()->get();
This returns an emtpy result set
Here is the query log from the above
array(2) {
[0]=> array(3) {
["query"]=> string(60) "select * from `catelogue` where `catelogue`.`id` = ? limit 1"
["bindings"]=> array(1) {
[0]=> int(96033)
}
["time"]=> float(0.91)
}
[1]=> array(3) {
["query"]=> string(289) "select `artist`.*, `cat_artist`.`LOOK_UP_TO_CAT_ID` as `pivot_LOOK_UP_TO_CAT_ID`, `cat_artist`.`LOOK_UP_TO_ARTIST_ID` as `pivot_LOOK_UP_TO_ARTIST_ID` from `artist` inner join `cat_artist` on `artist`.`id` = `cat_artist`.`LOOK_UP_TO_ARTIST_ID` where `cat_artist`.`LOOK_UP_TO_CAT_ID` is null"
["bindings"]=> array(0) { }
["time"]=> float(0.37) } }
This is all happening before I return the view and pass the data to the view
Everything else in the query is right apart from this where it's looking for null
where `cat_artist`.`LOOK_UP_TO_CAT_ID` is null
It should be this
where `cat_artist`.`LOOK_UP_TO_CAT_ID` = ?
Please help. I can't figure out where I have gone wrong
EDIT
Here are my DB tables - watered down as showing all cols would be a waste
CREATE TABLE IF NOT EXISTS `artist` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`ARTIST` varchar(255) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `ARTIST` (`ARTIST`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
CREATE TABLE `catelogue` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`CAT_NO` varchar(255) DEFAULT NULL,
`TITLE` varchar(255) DEFAULT NULL,
`BARCODE` varchar(15) DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `BARCODE` (`BARCODE`),
UNIQUE KEY `CAT_NO` (`CAT_NO`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cat_artist` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`LOOK_UP_TO_CAT_ID` int(11) NOT NULL,
`LOOK_UP_TO_ARTIST_ID` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`),
UNIQUE KEY `unique_index` (`LOOK_UP_TO_CAT_ID`,`LOOK_UP_TO_ARTIST_ID`),
KEY `LOOK_UP_TO_CAT_ID` (`LOOK_UP_TO_CAT_ID`),
KEY `LOOK_UP_TO_ARTIST_ID` (`LOOK_UP_TO_ARTIST_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Hopefully an answer can be found as to why it is putting is null in the where statement rather than the product ID
Also I have tested the resulting raw SQl by replacing is null with a product id and it does work in phpMyAdmin so the SQL been generated is correct up to the is null
This may sounds stupid, but I think it's beacuse your field names are in uppercase letters. so laravel cannot find the id column in attributes list in Project model. so it assumes you are search for null ids.
So at least rename ID columns to id(lowercase).
After lots of digging I found that I was using the wrong var to set the $primaryKey. I was using $primary_id. How or where I picked this up I don't know but it seems to be the root cause because I wasn't changing the primaryKey var but rather declaring a new one - Stupid user error
To Any one else finding this - double check your code.
Make sure you are assigning the correct variable.
Wrapping a pre tag around my var_dump helps to read a large obeject/array and helped me to find the issue
Related
I am following instructions from Bookmarks tutorial, and i have a problem with one of the queries.
I have baked all models from my database (like in tutorial) and now i want to prepare custom finder.
I have two tables Academic Teachers and Evaluations
CREATE TABLE evaluations (
ID int(10) NOT NULL AUTO_INCREMENT,
academic_teacher_ID int(10) NOT NULL,
framework_ID int(10) NOT NULL,
protocol_ID int(10) NOT NULL,
final_note DOUBLE,
room varchar(255),
PRIMARY KEY (ID)) ;
CREATE TABLE academic_teachers (
ID int(10) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
surname varchar(255) NOT NULL,
national_identification_number int(10) NOT NULL,
occupation varchar(4),
degree varchar(255),
department varchar(255),
PRIMARY KEY (ID)) ;
I want to find teachers, who at their last evaluation received a low note.
public function findLowNotes(Query $query, array $options)
{
return $this->find()
->distinct(['AcademicTeachers.id'])
->matching('Evaluations', function ($q) {
return $q->where(['Evaluations.final_note' < 3]);
});
But it wil find all the teachers who ever had any bad note. How should it be? Shall I somewhere use one of the ways of retrieving last ID that I found? Or there is a more clever way that will surely work? I am much confused how to combine it all together.
And - is it possible to join here with that final_note, so I could paginate it along with that teacher's data?
Yours sincerely,
Milven
This is not right.
return $q->where(['Evaluations.final_note' < 3]);
It should be.
return $q->where(['Evaluations.final_note <' => 3]);
I have two tables as below
table halte :
CREATE TABLE `halte` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nama` varchar(255) NOT NULL,
`lat` float(10,6) DEFAULT NULL,
`lng` float(10,6) DEFAULT NULL,
PRIMARY KEY (`id`)
)
table stops :
CREATE TABLE `stops` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_halte` int(11) DEFAULT NULL,
`sequence` int(2) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_halte` (`id_halte`)
)
I also have some other tables which don't cause any problems.
Halte table has many to one relation to stop. The problem is when i try to get rows from halte table using right join to table stops, Yii only returns unique rows. Yii won't return same halte's row more once even stop table has more than one record related to same row in halte table.
Here's my code
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
I have tried distinct(false) but no result.
I've also check debugger and it run right query i want :
SELECT `halte`.* FROM `halte` RIGHT JOIN `stops` ON halte.id = stops.id_halte WHERE `stops`.`id_rute`='1' ORDER BY `sequence`
I tried to run that query manually and it returned 29 rows which is what what i want. But in Yii, it only returned 27 rows because 2 rows is same record in halte table.
I know i can achieve this using yii\db\Query, but i want to use ActiveRecord.
Are there any way to work around this?
I would really appreciate your opinion/help.
Thanks.
Check the sql command generated by you active query
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
echo $haltes->createCommand()->sql;
or to get the SQL with all parameters included try:
$haltes->createCommand()->getRawSql();
And compare the code generated by ActiveQuery with your created manually ..
I have a simple ACL system in PHP and MYSQL started. I need help finishing it though...
I have 2 Database tables shown below...
user_link_permissions : Holds a record for every user, on every entity/link that permissions apply to...
--
-- Table structure for table `user_link_permissions`
--
CREATE TABLE IF NOT EXISTS `user_link_permissions` (
`id` int(100) NOT NULL AUTO_INCREMENT,
`user_id` int(30) NOT NULL,
`link_id` int(30) NOT NULL,
`permission` int(2) NOT NULL DEFAULT '0',
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2055 ;
intranet_links : Is basically the entity that the permission gives or revokes user access to
--
-- Table structure for table `intranet_links`
--
CREATE TABLE IF NOT EXISTS `intranet_links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text NOT NULL,
`url` varchar(255) DEFAULT NULL,
`notes` text,
`user_login` varchar(255) DEFAULT NULL,
`user_pw` varchar(255) DEFAULT NULL,
`active` int(2) NOT NULL DEFAULT '1',
`sort_order` int(11) DEFAULT NULL,
`parent` int(10) NOT NULL DEFAULT '1',
`local_route` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `local_route` (`local_route`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;
To save these permissions settings I have a matrix style grid like this below where each checkbox is a record in the user_link_permissions table...
I need help creating a simple ACL function in PHP which can check if a user has permission or not to view a link/entity based on the database results.
On page load I am thinking I can query the user_link_permissions DB table for all records with a matching user ID of the logged in user and store them to a session array variable.
A function could then use that array to check for a link/entity permission using that array value on the entity key.
I just can't visualize how it might look at the moment in PHP.
Any help please?
function aclCanAccess($user_id, $entity_id){
}
$entity_id = 123;
if(aclCanAccess(1, $entity_id){
// yes user can see this item
}else{
// NO user permission denied
}
I will leave writing the code to you for fun.
Assume you are storing all the previously queried permissions in a variable called $_SESSION['acl']
Your ACL function should:
check the session if you already queried that entity
if it is not set, read it from the db
in short
function..... {
if(!isset($_SESSION['acl'][$entity_id])) {
$_SESSION['acl'][$entity_id] = query here to return to you if he has access or not
}
return $_SESSION['acl'][$entity_id];
}
You can also read the entire array when you log in the user. That might also be appropriate. In that case you should be able to just
return $_SESSION['acl'][$entity_id];
But I would then try and catch an exception in case it is not set.
Hi I have these two tables that I want to join using relations in Yii, The problem is Im having a hard time figuring out how Yii relation works.
picturepost
id
title
link_stat_id
linkstat
id
link
post_count
I also have a working SQL query. This is the query I want my relation to result when I search when I want to get picturepost
SELECT picturepost.id, picturepost.title,linkstat.post_count
FROM picturepost
RIGHT JOIN linkstat
ON picturepost.link_stat_id=linkstat.link;
I want something like this when I search for a post.
$post = PicturePost::model() -> findByPk($id);
echo $post->linkCount;
Here's my table for extra info:
CREATE TABLE IF NOT EXISTS `picturepost` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` text COLLATE utf8_unicode_ci DEFAULT NULL,
`link_stat_id` char(64) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM;
CREATE TABLE IF NOT EXISTS `linkstat` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`link` char(64) COLLATE utf8_unicode_ci NOT NULL,
`post_count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `post_count` (`post_count`),
KEY `link_stat_id` (`link`)
) ENGINE=InnoDB;
Thanks in advance I hope I explained it clearly.
There are a few tutorial regarding this, and I won't repeat them, but urge you to check them out.
The easiest starting point will be to create your foreign key constraints in the database, then use the Gii tool to generate the code for the model, in this case for the table picturepost.
This should result in a class Picturepost with a method relations(),
class Picturepost extends {
public function relations()
{
return array(
'picturepost_linkstats' => array(self::HAS_MANY,
'linkstat', 'link_stat_id'),
);
}
This links the 2 tables using the *link_stat_id* field as the foreign key (to the primary key of the linked table).
When you are querying the table picturepost, you can automatically pull in the linkstat records.
// Get the picturepost entry
$picturepost = PicturePost::model()->findByPk(1);
// picturepost_linkstats is the relationship name
$linkstats_records = $picturepost->picturepost_linkstats;
public function relations()
{
return array(
'linkstat' => array(self::HAS_ONE, 'Linkstat', array('link_stat_id'=>'link')),
);
}
More on yii relations.
This assumes that you have an active record model Linkstat that represents data in table linkstat.
I'm working on a web site where users can post articles with this table structure :
CREATE TABLE IF NOT EXISTS `articles` (
`id_articles` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(10) unsigned NOT NULL,
`articles` text NOT NULL,
PRIMARY KEY (`id_articles`),
UNIQUE KEY `id_articles` (`id_articles`),
KEY `id_users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Each user can 'like' the articles.
Is that the right way below to create a 'like table' :
CREATE TABLE IF NOT EXISTS `articles_likes` (
`id_articles` int(10) unsigned NOT NULL,
`id_users` int(10) unsigned NOT NULL,
KEY `id_articles` (`id_articles`,`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It is correct but you will want to add separte indexes on id_articles and id_users (also you might want to name the columns 'id_article' and 'id_user' for sanity).
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article` (`id_article`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
The reason you want separate indexes is because in mysql if you create an index on columns (A, B) that index will be used in queries having in the where clause column A, or columns A and B.
In your case for example if you made a query "SELECT * FROM article_likes WHERE id_user=X" this query would not use an index.
An ever better option would be to add a combined index and a separate index on the second column from the combined index. Like this:
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article_user` (`id_article`, `id_user`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
This way you would have optimal performance on queries like 'WHERE id_user=X', "WHERE id_article=X', "WHERE id_article=X AND id_user=Y"
This is a valid way Chris. You can use COUNT() to match the id_articles in the articles_likes table against the current article you are viewing in articles.
$articles_id = 23;
mysql_query("SELECT COUNT(*) FROM articles_likes
WHERE id_articles = ".$articles_id);
You can also just leave COUNT() (MySQL) out and instantly know which users are the "likers" of the articles and use count() (PHP) on the returned Array to duplicate the effect of COUNT() in MySQL.
i would have a total of 3 tables. an articles table, and the user id could be a column in that for users who submit articles , but you need a separate user table since not all users will submit articles (i am assuming), and then a 3rd table for likes, that takes the primary key from users and the primary key from articles and uses them as foreign keys. so each time an article is liked, an entry is made in the 3rd table