i have posts table
id
type enum(A,Q)
title
content
and i need controllers questions_controller and answer_controller to use
please lead the right way to
1-
make 2 models (question and answer) and use 'posts' as model's table
2-
use post model in questions_controller and answer_controller
For me, it should be one table has one model
So better use
$uses = array('Post'); in your controllers.
Update:
As far I understood you want to filter the data depending from the type column. Actually your db model is wrong, because except if they are totally unrelated your answers need to belong to the question. This mean you need an extra column parent_id which will determine what is the parent node (question) and child nodes (answers).
If we have this assumption, then you can set a relation in the model like:
class Post extends AppModel {
...
var $belongsTo = array(
'Parent' => array('className' => 'Post','foreignKey' => 'parent_id', 'conditions' => 'Parent.parent_id IS NOT NULL')
);
...
}
So you automatically have Post and Post->Parent. But I think that it would be better to have 2 tables - one which holds the questions and another the answers.
Related
I have created a new extension with the extension builder which includes some tables and inline relations between some tables.
For reporting I need some queries where the selection condition is based on the related records.
Here I have difficulties to get the data (except doing raw queries, which seems wrong).
attempt:
do the query in the related records and extract the field which holds the uid of the parent records.
Problem: in the query result is no field with the uid of the parent record (although it is in the database).
This is understandable as there are no methods to get/set the relation. (But it does not change if I insert these methods.)
Also in the children record there is no TCA definition of the relation field except:
'parent' => [
'config' => [
'type' => 'passthrough',
],
],
which might be the reason the field can not be displayed in the record even if inserted in the showitem list.
attempt:
doing a join from the parent record.
Here I have not found any examples how to build a join.
There are other possibilities for a query, but the plainest seems this in the parent record repository:
public function getParentsByFilter($mainCondition,$subCondition) {
$parentQuery = $this->createQuery();
$parentQuery->matching(
$parentQuery->logicalAnd(
$parentQuery->equals('parent_field',$mainCondition)
// $childQuery->equals('children_field',$subCondition)
)
);
// $parentQuery->joinTable('tx_myext_domain_model_children', ...)
$parentQuery->setOrderings(['crdate'=> QueryInterface::ORDER_DESCENDING]);
$parentQuery->getQuerySettings()->setRespectStoragePage(false);
return $parentQuery ->execute();
}
Here I don't know how to join the children table.
I expect some methods like the commented lines, but have not found anything like it.
What's about the same configuration like in the table sys_category?
I have a many-to-many relation setup using a junction table in MySQL. Table Article is related to Activity via table Article_Activity.
In model Article I have a relation setup like this
public function getActivities()
{
return $this->hasMany(Activity::className(), ['id' => 'activity_id'])
->viaTable('article_activity', ['article_id' => 'id']);
}
When rendering a view for one Article I would like to display a GridView of all Activities related to that Article.
The way most people seem to this is to create a ActiveDataProvider and insert a query into it that fetches related data but that feel a bit redundant since I have the relation setup in the model and there should be a way to get a dataprovider from that.
My question is: Is there a way to get a yii\data\ActiveDataProvider or yii\db\Query based on a instantiated models relation that can be used to display all related records in a GridView?
You can actually call it like this:
$dataProvider = new ActiveDataProvider([
'query' => $article->getActivities(),
]);
If you call the get method directly you get a yii\db\ActiveQueryInterface which is what you need to provide as query to the ActiveDataProvider.
When you call the activities attribute like $article->activities the ActiveQueryInterface is executed and you get the records from the query results.
Based on you Article model you have the activities relation that get multiple Activity related to you Article
a normal dataProvider like
$dataProvider = new ActiveDataProvider([
'query' => Article::find()->joinWith(['activities'])->
where(['your_column'=> $your_value]),
]);
return activeRecord whit also the related activities
you can refer to the related models inside the dataProvider
$models = $dataProvider->models; // this is a collection of model related to the dataProvider query
// so the firts model is $model=models[0]
then for each of this you can obtain acyivities
$activities = $model->activities;
or value
$my_activity_field = $model->activities->my_activity_field
I am not sure why I can't get the columns from my other tables via my relations. I was thinking is it because of my scope? After i had a default scope in my models, everything seems to be out of place, even if i use resetscope() at some places. Some sections I can't get to my relation columns; when that happens, I'd have to use Model::model->findbypk(n)->name.. that doesn't look pretty.
the id shows if i don't have the relations, but the name is blank when i put the relation name.
CHtml::listData(Model::model()->findAll(),'product_id','main.product_name'),
my model defaultscope is pretty basic:
return array(
'condition'=>'store_id1=:store_id OR store_id2=:store_id' ,
'params' => array(':store_id' => $store_id)
);
You can change the way you use your model like below:
Model::model()->with('main')->findAll();
I'm trying to fetch a collection of read-only objects from NHibernate where all the properties come from a single table (Answers), with the exception of one property that comes from another table (Questions) in a many to one relationship. The fact it's two tables is an implementation detail that I want to hide, so I want the repository to return a sensible aggregate. The trouble is this requires I have two classes, one for each table, that NHibernate returns and then I have to select/map that into a third class that my repository returns. This feels a bit rubbish so instead I was hoping to have a mapping that joins the two tables for me but maps all the columns onto a single class. My mapping looks like this:
public QuestionAnswerMap()
{
ReadOnly();
Table("Question");
Id(x => x.Id).Column("questionId").GeneratedBy.Identity();
Map(x => x.AnswerShortCode).Column("AnswerShortCode");
Join("Answers", join =>
{
join.Fetch.Join();
join.KeyColumn("questionId").Inverse();
join.Map(x => x.QuestionId).Column("QuestionId");
join.Map(x => x.AnswerId).Column("AnswerId");
join.Map(x => x.MemberId).Column("MemberId");
});
}
The SQL this generates looks perfect and returns exactly what I want, but when there are multiple Answers that join to the same row in the Questions table, NHibernate seems to map them to objects wrongly - I get the right number of results, but all the Answers that have a common Question are hydrated with the first row in sql result for that Question.
Am I doing this the right way? NH is generating the right SQL, so why is it building my objects wrong?
because Join was meant to be this way. It assumes a one to one association between the two tables which are not the case.
Instead of a mapped Entity i would prefere a on the fly Dto for this:
var query = session.Query<Answer>()
.Where(answer => ...)
.Select(answer => new QuestionAnswer
{
QuestionId = answer.Question.Id,
AnswerShortCode = answer.Question.AnswerShortCode,
AnswerId = answer.Id,
MemberId = answer.MemberId,
});
return query.ToList();
One thing with which I have long had problems, within the CakePHP framework, is defining simultaneous hasOne and hasMany relationships between two models. For example:
BlogEntry hasMany Comment
BlogEntry hasOne MostRecentComment (where MostRecentComment is the Comment with the most recent created field)
Defining these relationships in the BlogEntry model properties is problematic. CakePHP's ORM implements a has-one relationship as an INNER JOIN, so as soon as there is more than one Comment, BlogEntry::find('all') calls return multiple results per BlogEntry.
I've worked around these situations in the past in a few ways:
Using a model callback (or, sometimes, even in the controller or view!), I've simulated a MostRecentComment with:
$this->data['MostRecentComment'] = $this->data['Comment'][0];
This gets ugly fast if, say, I need to order the Comments any way other than by Comment.created. It also doesn't Cake's in-built pagination features to sort by MostRecentComment fields (e.g. sort BlogEntry results reverse-chronologically by MostRecentComment.created.
Maintaining an additional foreign key, BlogEntry.most_recent_comment_id. This is annoying to maintain, and breaks Cake's ORM: the implication is BlogEntry belongsTo MostRecentComment. It works, but just looks...wrong.
These solutions left much to be desired, so I sat down with this problem the other day, and worked on a better solution. I've posted my eventual solution below, but I'd be thrilled (and maybe just a little mortified) to discover there is some mind-blowingly simple solution that has escaped me this whole time. Or any other solution that meets my criteria:
it must be able to sort by MostRecentComment fields at the Model::find level (ie. not just a massage of the results);
it shouldn't require additional fields in the comments or blog_entries tables;
it should respect the 'spirit' of the CakePHP ORM.
(I'm also not sure the title of this question is as concise/informative as it could be.)
The solution I developed is the following:
class BlogEntry extends AppModel
{
var $hasMany = array( 'Comment' );
function beforeFind( $queryData )
{
$this->_bindMostRecentComment();
return $queryData;
}
function _bindMostRecentComment()
{
if ( isset($this->hasOne['MostRecentComment'])) { return; }
$dbo = $this->Comment->getDatasource();
$subQuery = String::insert("`MostRecentComment`.`id` = (:q)", array(
'q'=>$dbo->buildStatement(array(
'fields' => array( String::insert(':sqInnerComment:eq.:sqid:eq', array('sq'=>$dbo->startQuote, 'eq'=>$dbo->endQuote))),
'table' => $dbo->fullTableName($this->Comment),
'alias' => 'InnerComment',
'limit' => 1,
'order' => array('InnerComment.created'=>'DESC'),
'group' => null,
'conditions' => array(
'InnerComment.blog_entry_id = BlogEntry.id'
)
), $this->Comment)
));
$this->bindModel(array('hasOne'=>array(
'MostRecentComment'=>array(
'className' => 'Comment',
'conditions' => array( $subQuery )
)
)),false);
return;
}
// Other model stuff
}
The notion is simple. The _bindMostRecentComment method defines a fairly standard has-one association, using a sub-query in the association conditions to ensure only the most-recent Comment is joined to BlogEntry queries. The method itself is invoked just before any Model::find() calls, the MostRecentComment of each BlogEntry can be filtered or sorted against.
I realise it's possible to define this association in the hasOne class member, but I'd have to write a bunch of raw SQL, which gives me pause.
I'd have preferred to call _bindMostRecentComment from the BlogEntry's constructor, but the Model::bindModel() param that (per the documentation) makes a binding permanent doesn't appear to work, so the binding has to be done in the beforeFind callback.