I have three tables.
User
id
Group
id
UserGroup
user_id
article_id
date_joined
Now I have three separate models to set up the relationship.
// User Model
<?php
class User extends Doctrine_Record
{
// define table columns in this function
public function setTableDefinition() {
}
// setup some options
public function setUp() {
$this->hasMany('Group as Groupss', array(
'local' => 'user_id',
'foreign' => 'group_id',
'refClass' => 'UserGroup'
));
// causes 'created_at' and 'updated_at' fields to be updated automatically
$this->actAs('Timestampable');
}
}
// Group Model
<?php
class Group extends Doctrine_Record
{
// define table columns in this function
public function setTableDefinition() {
}
$this->hasMany('User as Users', array(
'local' => 'group_id',
'foreign' => 'user_id',
'refClass' => 'UserGroup'
));
}
}
// UserGroups
<?php
class UserGroup extends Doctrine_Record
{
public function setTableDefinition()
{
$this->hasColumn('user_id', 'integer', 4, array(
'primary' => true
)
);
$this->hasColumn('achievement_id', 'integer', 4, array(
'primary' => true
)
);
$this->hasColumn('date_completed', 'timestamp', 25);
}
}
and now all i want to do is build the relationship inside my controller:
$user = Doctrine::getTable('User')->findOneByEmail('abcd123#gmail.com');
$group = Doctrine::getTable('Group')->findOneByID('1');
$user->Group = $user;
Both SQL commands are returning one result and when I run the controller I get the following error:
Fatal error: Uncaught exception 'Doctrine_Record_UnknownPropertyException' with message 'Unknown record property / related component "User" on "Group"' in
The refclass option in the User and Group classes should most likely be UserGroup and not UserGroups (Doctrine doesn't understand the difference between singular and plural). You should also invoke the parent::setUp() method in each of the setup() methods you declare.
There's an extensive amount of documentation on many-many relationships in the official manual. (Which uses the user-group relation as an example)
EDIT:
I noticed some severe problems with the code while going through it again:
Your UserGroup table has an article_id column, but no group_id column.
The declared relation to the Group model under the name Groupss, this making the relation $user->Group unknown.
Finally, you should assign the user to an array of groups like $user->Groups[] = $group
Related
I have a relationship
Candidate -> Vacancy -> User
Candidate:
class Candidate extends Model
{
public function vacancy()
{
return $this->belongsToMany(
Vacancy::class,
'vacancy_has_candidate',
'candidate_id',
'vacancy_id'
);
}
}
Vacancy:
class Vacancy extends Model
{
public function candidate()
{
return $this->belongsToMany(
Candidate::class,
'vacancy_has_candidate',
'vacancy_id',
'candidate_id'
);
}
public function manager() {
return $this->hasMany(User::class, 'manager_id');
}
}
User:
class User extends Authenticatable
{
public function vacancy()
{
return $this->belongsTo(Vacancy::class, 'manager_id');
}
}
I want to display in СRUD candidates the field of the relationship in which I call the manager method with the output of the field from the User model.
for example
class CandidateCrudController extends CrudController
{
....
public function setupCreateOperation()
{
$this->crud->addFields([
[
'name' => 'vacancy',
'type' => 'relationship',
'label' => 'Vacancy',
'model' => Vacancy::class,
'entity' => 'manager', <- this method in Vacancy model
'attribute' => 'title', <- this column name in User
'ajax' => true,
]
]);
...
I get an error
"Looks like field vacancy is not properly defined. The manager() relationship doesn't seem to exist on the App\Models\Candidate model"
I can’t understand why the backpack is looking for a manager method in Candidates, although in the model I indicated a Vacancy in which this relationship method exists. And how to do it right?
KorDEM.
You will not be able to achieve that as per Backpack Documentation:
entity is the method that defines the relationship on the current model, in your case App\Models\Candidate is the CrudController model. So entity there should be the vacancy relation.
If you are using Backpack\PRO paid addon you should be able to list the vacancies with the desired information by using something like:
$this->crud->addField([
'name' => 'vacancy',
'subfields' => [
['name' => 'manager']
]
]);
If you need aditional pivot fields you need to provide ->withPivot in the relation.
Check BelongsToMany documentation on Backpack website
How to implement this feature in the Phalcon? Doctrine has this. I want something similar like that. My office table in the database:
Id (PK) | ParentId | Name
I want a function like:
Office::findFirst()->children();
I've tried to define a Many-to-One relationship in my model but it always returns an empty array.
In your model:
namespace Models;
class ProductCategories extends BaseModel
public function initialize()
{
$this->hasMany('id', 'Models\ProductCategories', 'parent_id', [
'alias' => 'children',
'params' => [
'order' => 'position ASC',
'conditions' => 'active = 1',
]
]);
}
}
Note the full namespace.
Usage:
$parent = \Models\ProductCategories::findFirst();
print_r($parent->children->toArray());
More info: https://docs.phalconphp.com/en/3.1/db-models-relationships
I am sorry if the title is a bit confusing, I just don't know how this is properly called. I have a table structure like this for my CakePHP project.
users id, name, surname, userrecords
userrecords id, user_id, records_id
records id, description
I understand that to access the userrecords middle table in my users view I have to do something like
$user['userrecords']['id'];
How can I neatly access description in records table through a users view?
You didn't specify whether you're using CakePHP 2.x or 3.x, so I provided solutions for both.
The relationship you are referring to is called a "Has And Belongs To Many" relationship. Since both of your model are associated to a linking table (userrecords), you can freely associate as many records to as many users as you want.
First, I would consider renaming your 'userrecords' table to 'users_records' to play nicely with CakePHP.
First, define your relationship within your Users model:
// Using CakePHP 2.x:
class User extends AppModel {
public $actsAs = array('Containable'); // Instantiate Containable behavior
public $hasAndBelongsToMany = array(
'Record' =>
array(
'className' => 'Record',
'joinTable' => 'users_records',
'foreignKey' => 'user_id',
'associationForeignKey' => 'record_id'
)
);
}
// Using CakePHP 3.x:
class UsersTable extends Table
{
public function initialize (array $config)
{
$this->belongsToMany('Records', [
'joinTable' => 'users_records' // Defines our linking table
]);
}
}
Now, we must define our relationship within our Records model:
// Using CakePHP 2.x:
class Record extends AppModel {
public $actsAs = array('Containable'); // Instantiate Containable behavior
public $hasAndBelongsToMany = array(
'User' =>
array(
'className' => 'User',
'joinTable' => 'users_records',
'foreignKey' => 'record_id',
'associationForeignKey' => 'user_id'
)
);
}
// Using CakePHP 3.x:
class RecordsTable extends Table
{
public function initialize (array $config)
{
$this->belongsToMany('Users', [
'joinTable' => 'users_records' // Defines our linking table
]);
}
}
Now, we can access the associated records freely from each model using the ORM's contain method:
// Using CakePHP 2.x:
// Getting 'User' and associated 'Record' models in Controller:
$this->loadModel('User');
$this->User->find('all', array('contain' => 'Record'));
// Getting 'Record' and associated 'User' models in Controller:
$this->loadModel('Record');
$this->Record->find('all', array('contain' => 'User'));
// Using CakePHP 3.x:
// Getting 'User' and associated 'Record' models:
$users_table = TableRegistry::get('Users');
$users = $users_table->find()->contain('Records')->all();
// Getting 'Record' and associated 'User' models:
$records_table = TableRegistry::get('Records');
$records = $records_table->find()->contain('Users')->all();
Read the Cookbook, it will make your life a million times easier:
CakePHP 2.x Containable Behavior
CakePHP 2.x Has And Belongs To Many Relationship
CakePHP 3.x belongsToMany Relationship
CakePHP 3.x Retrieving Associated Data
CakePHP 3.x Eager Loading Associations
Read this,this may be helpful for you
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Because your table structure as below :
User -> UserRecord -> Record
So that you can only get [Record] via [UserRecord]
You should set recursive property in find command.
Please refer for more information about recursive at this link : what is the meaning of recursive in cakephp?
I hope this answer doesn't misunderstand your question.
I have trouble using ACL. In my CoreUsersController i make the following call:
if(!$this->Acl->check('User::'.$user['User']['id'], 'CoreUser', 'read')) {
die('PERM DENIED');
}
The ACL is included as component in my AppController. The Database-Tables looks like:
table "acos"
table "core_groups" (as aros)
table "aros_acos" as connection between core_groups and acos.
Here is the Error Thrown:
Error: Table aros for model Aro was not found in datasource default.
And my Code:
1. User-Model:
App::uses('AuthComponent', 'Controller/Component');
class CoreUser extends AppModel {
public $useDbConfig = 'default';
public $useTable = 'core_users';
public $hasAndBelongsToMany = array(
'MemberOf' => array(
'className' => 'CoreGroup',
'joinTable' => 'core_users_groups',
'foreignKey' => 'user_id',
'associationForeignKey' => 'group_id'
)
);
public $name = 'User';
public $actsAs = array('Acl' => array('type' => 'both'));
public function parentNode() {
// stuff in here should be correct
}
}
2. Group-Model:
App::uses('AppModel', 'Model');
App::uses('AuthComponent', 'Controller/Component');
class CoreGroup extends AppModel {
public $useDbConfig = 'default';
public $useTable = 'core_groups';
public $hasAndBelongsToMany = array(
'Member' => array(
'className' => 'CoreUser',
'joinTable' => 'core_users_groups',
'foreignKey' => 'group_id',
'associationForeignKey' => 'user_id'
)
);
public $name = 'Group';
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
return null;
}
}
My Question: How to tell ACL to use "core_groups"-Table instead of "aros"-table? Note: I added "ActsAs" as suggested by the Cake-Book to both Models!
If you would like to proceed with Cake's ACL, then it is better to have three separate tables:
1. aros
2. acos
3. aros_acos
These can be generated using the AclShell:
./Console/cake schema create DbAcl
Using one of your app's model as an ARO or ACO is not advised as ARO and ACO models are implemented as a tree structure. These should be separate from the models in your app that 'actsAs' an ACO / ARO.
When you do attach the Acl behavior in the $actsAs property to your User/Group models, the Acl behavior's callbacks kick in. These use the parentNode() methods defined in your User/Group models to create an ARO reference to the rows created in your User/Group models. These references are stored in the ARO table separately, pointing to the actual User and Group. Hence, the ARO table is necessary.
I would recommend you go through the ACL tutorial in the book as your implementation will be quite similar. Just be careful about using the HABTM relationship between User and Group, as that will need a bit of tweaking.
I have these models:
class Prefix extends AppModel {
public $displayField = 'prefix';
public $hasMany = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'prefix_id',
'dependent' => false,
),
);
}
class State extends AppModel {
public $displayField = 'name';
public $belongsTo = array(
'Prefix' => array(
'className' => 'Prefix',
'foreignKey' => 'prefix_id',
),
);
}
Then I have this admin_add method, from the automatic scaffolder:
public function admin_add() {
if ($this->request->is('post')) {
$this->Peefix->create();
if ($this->Prefix->save($this->request->data)) {
$this->redirect(array('action' => 'index'));
} else {
// Error message
}
}
$states = $this->Prefix->State->find('list');
$this->set(compact('states'));
}
I also have the list of them in my form:
<?php echo $this->Form->input('State', array('multiple' => 'checkbox', 'type' => 'select',)); ?>
Now I can set the States for the Prefix. However, when I submit the form, the selection disappears. It is not saved in the database.
What did I do wrong?
You linked the models as if there is only one state per prefix, and many prefixes "assigned" to one state. That means you cannot use 'multiple' => 'checkbox'. So either remove this or change model associations to HABTM.
First, both foreign keys for hasMany and belongsTo must be the same. If in the parent model you provided invoice_circle_id as the key, then the same must be provided in the child model also. Obviously, that field must exist in the child table. See this for more info http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Second - you might want to use the saveAll() or saveAssociated() method for linked model data saving. Again - http://book.cakephp.org/2.0/en/models/saving-your-data.html contains all the ifnormation you need.
As for naming the input fields for hasMany, you name them like this:
$this->Form->input('ParentModel.fieldname');
$this->Form->input('ChildModel.0.fieldname');