namespace Model;
class newsModel extends \DB\Cortex
{
protected
$db = 'AppDB1',
$table = 'news';
}namespace Model;
class authorModel extends \DB\Cortex
{
protected
$db = 'AppDB1',
$table = 'author';
}You are talking about a one-to-many relation. The news was written by one author. An author as written many news.
The one to many relation can be looked up from the docs -> https://github.com/ikkez/f3-cortex/tree/master#setup-the-linkage
Type 1:m, it's also right in the screenshot you'll see there. (it's belongs-to-one <> has-many)
'news' => array(
'has-many' => array ('\NewsModel','author'),
),'virtualField' => array(
'relationType' => array('\Namespace\ClassName','foreignKey'),
),Defining a foreign key forbelongs-to-*is optional.
namespace Model;
class authorModel extends \DB\Cortex
{
protected
$fieldConf = array(
'news' => array(
'has-many' => array ('\Model\NewsModel','news'),
),
),
$db = 'AppDB1',
$table = 'author';
}Internal Server Error
array_key_exists() expects parameter 2 to be array, null givenThe reason why I´m confused is, following this documentation steps how are the table linked together
as the relation is in the third table? Further I do not have a foreign key in author or news table as it´s in
rel_author_news.
As said, sorry for asking stupid questions your documentation is great, maybe I´m just sitting for to long in front of my computer …
'news' => array(
'has-many' => array ('\NewsModel','author'),
), // --------------------------------^ required
'author' => array(
'belongs-to-one' => array ('\AuthorModel','id'),
), // -----------------------------------------^ optional'author' => array(
'belongs-to-one' => '\AuthorModel' // short style with id as default fkey
),belongs-to-* is optional."class rel{
function Content(\Base $f3){
$author = new \Model\authorModel();
$author->load(array('city = ?','Windsor'));
$news = new \Model\newsModel();
$news->text = 'Hello World';
$news->author = $author;
$news->save();
$news->load();
echo $news->author->name;
}
}SELECT r.*, news.*
FROM rel_author_news r
INNER JOIN news
ON news.id = r.newsid
WHERE r.authorid = 2class news_author_relation{
public function get_news_ids($authorId){ $f3=Base::instance(); $relation = new \Model\relModel(); $records = $relation->find(array('authorid = ?', $authorId)); $finds = $records->getAll('newsid');
return $finds; }
public function get_news(){
$f3=Base::instance();
$Ids = $this->get_news_ids($f3->get('PARAMS.autorId')); $news = new \Model\newsModel(); $newstext = $news->find(array('id in (?)',$Ids)); foreach ($newstext as $obj) echo $obj->text . '<br>'; }}
$f3->route('GET /news/@autorId','news_author_relation->get_news');'news' => array(
'has-many' => array ('\NewsModel','author','rel_author_news'),
),
'author' => array(
'has-many' => array ('\AuthorModel','news','rel_author_news'),
) $news = new \Model\newsModel();
$result = $news->has('author',array('id = ?',2))->find();class new_post{
function save(\Base $f3){
$author = new \Model\authorModel(); $author->name = "bert brecht";
$author->mail = "b...@web.com";
$author->city = "berlin";
$author->save();
$news = new \Model\newsModel();
$news->title = "A book";
$news->text = "Some text";
$news->save();
$relation = new \Model\relModel();
$relation->author = $author->id;
$relation->news = $news->id;
$relation->save();
}
}if(!$author->news)
$author->news = array($news);
else
$author->news[] = $news;
$author->save();
You don't need no relModel at all your can delete that.
rel_author_news). Table joins are made when it's possible and reasonable. At the end you usually use the models methods to define your query. check the filter() and has() methods. There are also a lot more features to discover in the API docs. If there is something to improve in the docs, or you have questions, I'm here :)$table = 'users'$results[0]->title; // '10 Responsive Images Plugins'and even reorder you collection on this fields $news->copyfrom('POST','title;text');if(!$author->news)
$author->news = array($news);
else
$author->news[] = $news;
$author->save();or you have questions, I'm here :)
I think my main problem is/was if configuration field relations are not correct, things will not work as expected, it took some time forme to show respect to them.Further after some time I´ve recognized that cortex is happy if you do not do to much. In otherwords it cares about what is needed regarding relations – the moment I setup relationship models I messed things up.
Questions:
Means we can pass in fields which should be copied from POST? In other words the security issue from f3 SQL Mapper is already solved here? – This would be great to see in F3 core!$news->copyfrom('POST','title;text');
- I´m unsure if at some points it would be easier for me to just create a mysql view which joins tables than dealing with configuration fields. But on the other hand with views one would loose the ability to simple switch the underlaying database system.
- If I´m using fluent mode without ::setup() method Cortex will not be able to create relationship fields/tables as therefore configuration fields are needed, right?
- I cannot follow your given advise some posts above:
Is what you´re doing here described at: many-to-many, bidrectional?if(!$author->news)
$author->news = array($news);
else
$author->news[] = $news;
$author->save();
- My problem is I don´t understand what is happening with the array you are passing in.
well every relationship configuration is made with one field definition in each model. That shouldn't be too much and with only 3 relation types (belongs-to-one, has-one, has-many) the config should stay clear and easy to do.
… to filter the copyfrom fields, but to define them with a simple array would be nice addition yeah :)
- I´m unsure if at some points it would be easier for me to just create a mysql view which joins tables than dealing with configuration fields. But on the other hand with views one would loose the ability to simple switch the underlaying database system.
One idea I had once was to add a feature that cortex automatically creates the Views. But views don't aid in every situation and it's hard to make this all cross-platform compabile somehow. At the end the cortex runs fine with building it's own queries and adding joins when searching through relations. Like I said above, only 3 relation types shouldn't be too hard to configure, but maybe I'm already too much into it to see the obvious lacks in the docs.
- I cannot follow your given advise some posts above:
Is what you´re doing here described at: many-to-many, bidrectional?if(!$author->news)
$author->news = array($news);
else
$author->news[] = $news;
$author->save();yes, it's many-to-many. You asked for a config that uses your 3 tables. I told you that you actually want a one-to-many relation, with no 3rd table in-between, but I thought that you don't care :D
'color' => array( 'belongs-to-one' => '\Model\color', ), 'fruit' => array(
'has-many' => array('\Model\fruit','color'),
), $color = new \Model\color();
$color->name = "green";
$color->save();
$fruit = new \Model\fruit();
$fruit->name = "Kiwi";
$fruit->color = $color;
$fruit->save(); $fruit = new \Model\fruit();
$fruit->load(array("name = ?", "kiwi"));
echo "A " . $fruit->name . " is " . $fruit->color->name;
echo "<hr>";
$color = new \Model\color(); $color->load(array("name = ?", "green")); $all = $color->castField('fruit'); echo "> " . $color->name . " is a " . $all[0]['name'];A Kiwi is green
-
> green is aIn "Color" table, field "fruits" has Null.
– Is there a way to let cortex save also the counterpart relation in one shot where I saved the fruit in code example A) ?
echo "> " . $color->name . " fruits are: ";
if ($color->fruit)
foreach($color->fruit as $fruit)
echo $fruit->name.", ";
'fruit' => array(
'has-many' => array('\Model\fruit','color'),
),
The field $color->fruit "has many" Fruit models... how could "many" be displayed? of course it must be an array here.
A Kiwi is green
> green fruits are: Kiwi,
A Red Tomato is red
> red fruits are: Red Tomato, Chili,$fruitModel = new \Model\Fruit();
$fruits = $fruitModel->has('color',array('name = ?','red'))->find();
if ($fruits) {
echo "> Available fruits, which are red: ".implode(',',$fruits->getAll('name'));
} else {
echo "> There are no red fruits in store.";
}
You can also add multiple has-conditions to different relations:
A Designer XY has designed many font families like "Helvetica", this Family can have many "SubFamilies" like "Condensed"
or "Extended". Each Subfamily has different weights like "regular", "bold", "boldItalic" and so on. The Diagramm shows
configuration fields which can also be seen here:
$designer = new \Model\designer;
$result = $designer->load(array('_id = ?', 1));
if ($result)
$json = $result->cast(NULL, 3);
if(!$family->designer) $family = new \model\ family;
$family->erase(array('_id = 1'));
- Does this configuration layout makes sense to you?
- Do I need the configuration "family" in "weights" to see to which family weights belong to?
In other words can I cast all subfamilies and weights a family has without this configuration field as I already have the relation through subfamily?
- If I´d like to know all things a designer did I would cast his relations down the road
$designer = new \Model\designer;
$result = $designer->load(array('_id = ?', 1));
if ($result)
$json = $result->cast(NULL, 3);
In which case would I use castAll(); cast() seems to do the job.
- Let´s say I added some designers to one font as they worked as team:
if(!$family->designer)$family->designer = array($designer);else$family->designer[] = $designer;
How would I remove one special ID again? For example Family->designer holds IDs "1;2;3" how would I remove '3' later?
Do I just set the relation again but only with "1" and "2"?
- Is it possible to add new records in "batch"? Let´s say I´ve uploaded a bunch of files which are "weights". I will receive an assoc array which should go into "weight". Do I just repeat save() and reset() in an foreach loop to iterate through the array?
- Let´s say I delete a family. Is it possible to tell Cortex to delete the relations as well, or do I have to take care if something is erased that other models are updated as well?
$family = new \Model\family();
// setup delete cascade
$family->onerase(function($self){
$sf = new \Model\SubFamily();
$sf->erase(array('family = ?',$self->_id));
$w = new \Model\weights();
$w->erase(array('family = ?',$self->_id));
return true;
});
public function __construct() {and repeat that for your subfamily model, that deletes its weights.
$this->onerase(function($self){
$subFamilies = $self->SubFamily;
if ($subFamilies)
foreach($subFamilies as $subFamily)
$subFamily->erase();
return true;
});
parent::__construct();
}
Buff, that´s a lot. As it´s mostly you who comes to help regarding Cortex I made another donation.-> go and get two crates of beer for you and your friends, weekend is coming!!
'designer' => array(
'has-many' => array('\Model\designer','family'),
), 'family' => array(
'has-many' => array('\Model\family','designer'),
),Designer | Family
1 3
2 3
3 3 public function delete() {
$f3 = \Base::instance();
$this->erase(array("_id = ?",3));
}