To make relationship between users was created a table that looks like.
sql
CREATE TABLE `friends`(
`from` INT NOT NULL,
`to` INT NOT NULL,
UNIQUE INDEX(`from`, `to`)
);
As you may know - field from and to is a keys of user_id from users table.
I'm using Kohana 3.09 with its default module Auth.
Question is...
*How to make ORM functionality around relations of users with (default) Model_User class?*
Is there any needle to create additional class or perhaps i had some mistakes with relations one_to_many trouth and many_to_many trouth cause it did not work.
Please help.
My best regards.
You should check out this section of the documentation:
http://kohanaframework.org/guide/orm/relationships#hasmany
You'll need something like this within your user class
protected $_has_many = array(
'friends' => array(
'model' => 'user',
'through' => 'friends',
'far_key' => 'from',
'foreign_key' => 'to',
)
);
These options are used at this part in the source code.
Related
I am sure someone has to have done this before - looking at the previous queries it possibly cannot be done with Fluent - but here goes:
I have the following mappings
As you can probably spot - this is not going to work because the keys on the child table do not match the parent table and so the error will be that the number of fields on the foreign key contract don't match. However, I cannot change the underlying tables (and the relationship is a valid one). Is there a way around this in fluent nhibernate so I can somehow ignore the expected join on both composite fields and only join on the one which matches (i.e field_one?) Hibernate expects that field one and field two are present on both mappings.
public ParentMap()
{
Table("dbo.SOMEPARENT");
OptimisticLock.None();
LazyLoad();
CompositeId()
.KeyReference(x => x.FieldOne, x => x.Access.CamelCaseField(Prefix.Underscore), "field_one")
.KeyReference(x => x.FieldTwo, x => x.Access.CamelCaseField(Prefix.Underscore), "field_two");
HasMany(x => x.ChildData)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan()
.KeyColumns.Add("field_one")
.NotFound.Ignore();
}
public ChildDataMap()
{
Table("dbo.SOMECHILD");
OptimisticLock.None();
LazyLoad();
CompositeId()
.KeyProperty(x => x.FieldOne, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_one"))
.KeyProperty(x => x.FieldTwo, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_two"))
.KeyProperty(x => x.FieldThree, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_three"))
.KeyProperty(x => x.FieldFour, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_four"));
Map(x=>x.DontExecTrigger).Column("dont_exec_trigger").Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.DateField).Column("date_field").Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.DataField).Column("data_field").Access.CamelCaseField(Prefix.Underscore);
References(x => x.Parent)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.All()
.Fetch.Select()
.Columns("field_one")
.NotFound.Ignore()
.Not.LazyLoad();
}
From a purely database point of view, if a ChildDataMap FieldOne value always appears in ParentMap FieldOne and FieldOne is unique in ParentMap then there is a foreign key from the former to the latter. But also it means FieldOne is a candidate key of (unique in) ParentMap.
You should declare the FK and UNIQUE database constraints. You say you can't change the table but if the constraint is valid then it is not going to affect any useres of it. That ought to allow you to declare that ChildDataMap FirstOne References ParentMap FirstOne. The two-column set can still be declared PK (assuming it is). But if ParentMap FieldTwo is also unique, it should be declared UNIQUE also and so become available as one-column FK target.
Maybe the UNIQUE constraint and/or FK are already declared. Maybe you should just be declaring the corresponding unique property for FirstOne in ParentMap. The KeyColumns.Add ought rely on its being there and allow you to declare the References in ChildDataMap. But I guess that's where your code is not valid.
If Hibernate doesn't automatically join on same-named fields then you could just not declare the References and do your own join on the one field to get a set of references of which of course there will be only one element.
It's not clear what you mean by "you can't change the tables" (does that include, you can't have valid constraints added?) or "the relationship is a valid one" (does that mean, FieldOne in Parent is unique?). It would also help if you posted all the relevant code: namely the table delarations including constraints.
If you can have a new table defined, you can add StricterParentMap with the added constraints and have ParentMap declared as a view of it. This wouldn't affect others' use of it and might not count as "can't change".
Hello everyone and thanks for reading , i have little problem , i installed the yii user extension.
I created another table that has a relationship with the user table.
Yii created the relationships with the "user" table automatically but when i try to use the relationship it gives me the below message;
include(Users.php): failed to open stream: No such file or directory
Could this be because User Model is not with the other models but instead in Modules/User.....
How can i make it work ?
eg
array(
'header' => __('Title'),
'name' => 'id_employer_contract',
'value' => '$data->user->username',//user is the name of relationship
),
When trying to access the User.php model from outside of the User module, the file has not been imported yet.
If you look at the init() method of the UserModule.php file, you'll see that the User.php file gets imported via the user.models.* statement.
There are a few different way to import this file from other parts of your system:
Add application.modules.user.models.* to the import section of your main.php. This will make it available everywhere in your application
Call Yii::import('application.modules.user.models.*'); right before the area of code depending on User.php
Call Yii::app()->getModule('user'); right before the area of code depending on User.php. This will call the init() method in the User module.
Look at "include(Users.php): failed"
You can change the relation mapping (auto generated by Gii) from this:
'user' => array(self::BELONGS_TO, 'Users', 'user_id')
To this:
'user' => array(self::BELONGS_TO, 'User', 'user_id')
That should do the trick.
In another version of Yii the according model might be YumUser instead of User when creating your relation, did the job for me:
'user' => array(self::BELONGS_TO, 'YumUser', 'user_id')
The problem that you have is that the Table name for users is called "users" so when yii is resolving this for model generation it would resolve the user model to be "Users" however the yii-user module extension has the model as "UserModel" in a file named User.php
This means that in essesnce the file named Users.php does not exist.
To resolve this just change the relationship in your new model to'user' => array(self::BELONGS_TO, 'User', 'User'), and not 'user' => array(self::BELONGS_TO, 'Users', 'User'),
I'm trying to use the following inside my model:
create!(
:title => entry.title,
:link => entry.url,
:published_date => entry.published,
:entry_id => entry.id,
:category => thing,
:author => entry.author,
:user_id => user.id
)
This fails with Mysql2::Error: Duplicate entry '0' for key 'PRIMARY' when adding anything past the first entry since the id column is being set as 0. Is there a way to auto-increment the id using the above code?
Thanks
You should never need to manually specify the ID when creating new instances; Rails will automatically create the auto-incrementing column to handle generating unique IDs for you.
In this case, if you have tampered with the ID column and changed its type, the easiest way to reset this is to simply recreate the table.
I've started Yii a month ago and am finding it very intuitive, yet somehow confusing regarding widgets.
In the app i'm developing, although I sometimes use Active Record, I cannot use it's relations as I am using MyIsam (and this cannot be changed) and it has no support for foreign keys.
My issue is I have a CGridView and want to add custom data to it, but am having issues.
It is a 1-to-many relationship with the FK in the right model, but as I said, I cannot use AR's magic.
I have this, an Applications Model and a Profile model. The Profile model has an application FK.
I got a function so when I'm rendering the CGrid I can fetch the name of each Application instead of its *id_app*.
public function appName($id){
$app= Yii::app()->db->createCommand()
->select('name')
->from('tbl_aplications a')
->where('a.id=:id_app', array(':id_app'=>$id))
->queryRow();
return $app;
}
In the auto-generated templates, in the Profile Admin.php view, I got:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'profile-application-grid',
'dataProvider'=>$model->search(), //maybe the issue is with this criteria? It is currently 'as-is' after the template generation
'filter'=>$model,
'columns'=>array(
'id',
'name',
array(
'name'=>'id_app',
'header'=>'Aplication',
And here is my issue, I've tried (and all sorts of variations):
'value' => 'ProfileApplication::model()->appName($data->id_app)',
'value' => 'ProfileApplication::model()->appName(id_app)',
'value' => 'ProfileApplication::model()->appName("id_app")',
and all I get is null as a result because it is passing the actual string instead of each row's value. If I pass a direct ID to the function's query, it returns correct value, like ->where('a.id=:id_app', array(':id_app'=>3))
Is it the search criteria that needs to be altered?
I've found similar questions but all of them use AR such as Profile->application or something along those lines and I as I said, I cannot use it due to MyIsam restrictions.
Any tips are appreciated to this newcomer, or links to a solution regarding a similar issue .
To use the value attribute such as that you need, as PrplHaz4 said, a data provider. Then, the $data variable is what has the magic, and it must be used in a string because it is eval()'ed behind the scenes. Here is an example of what you are trying to do:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'item-grid',
'dataProvider'=>$model->search(),
'columns'=>array(
array(
'name' => 'id',
'header' => 'Item ID',
),
array(
'name' => 'category_search',
'header' => 'Category',
'value' => '$data->category->name',
),
),
)); ?>
That grabs the name attribute of the related item category model. In the relations() function of the item model:
return array(
'category'=>array(self::BELONGS_TO, 'ItemCategory', 'category_id'),
);
And in the relations() function of the item category model:
return array(
'items'=>array(self::HAS_MANY, 'Item', 'category_id'),
);
You should still be able to use ActiveRecord relations with MyISAM, I beleive the only difference is that with MyISAM, if you use a model generator (gii or cmd line), it will not automatically create the relations. Instead, you will have to specify the relation yourself in the Profile model. This is effectively creating a "soft" fk for use with AR.
public function relations()
{
return array(
'applications'=>array(self::HAS_MANY, 'Applications', 'id_app'),
);
}
That will not entirely solve your problem though, because you will need to use a dataprovider that brings the application models along with the profile models. Something like this:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'profile-application-grid',
'dataProvider'=>Profile::model()->with('Applications'),
'filter'=>$model,
'columns'=>array(
'id',
'name',
array(
'name'=>'applications.name',
'header'=>'Application',
),
Sorry ... my english is bad, so my question could be absolutely not clear.
I have this tables:
Groups
Users
Reports
Relations:
Groups 1 -> N Users 1 -> N Reports
In the admin view of report I'm using a CGridView.
i'm actually able to show user name. ... but what about show group.name ?
How to setup relations ?
How to setup CDbCriteria ?
I already have this relation In Report model:
'user' => array(self::BELONGS_TO, 'Users', 'userId'),
And this in User model
'group' => array(self::BELONGS_TO, 'Gruppi', 'groupId'),
In Report Model I have this:
$criteria=new CDbCriteria;
$criteria->with = array ('user');
You should be able to get the group.name like this(from report's admin view):
user.group.name
And your current relations will do, also you do not have to use any criteria.
You can also use like this:-
$criteria->with = array('user', 'user.group');
group.name
One more solution for the problem. (Tested)