I am relatively new to CakePHP, and I am writing a CakePHP application which currently has an Author model and a Book model. Author and Book both have a many-to-many relationship.
However, I would like to additionally, for every author-book relationship, have a corresponding link to that author's blog where they reflect upon their experiences writing that book.
If that was confusing, the following paragraphs try to elaborate to make my situation more clear:
For every author, there will be one article about their experiences for each book. To look at this relationship in reverse, this means that for every book, there will be one corresponding link, per author (given that books can have multiple authors), where that author describes his/her experience writing the book.
In other words, for every single (Author, Book) pair, I would like to be able to store a related URL.
In more fancy, abstracty math terms that I will use horribly and improperly: I have an undirected graph, where every vertex is an Author or a Book, and every edge has an Author for one vertex and a Book for the other. That sounds kind of confusing, but (I think) it describes my situation as precisely as I can make it.
Given the above description, I want to know if I can attach arbitrary data to any given edge of that relation, and retrieve it later.
Currently I have a third model, AuthorBook, which acts the graph edge.
Author has a hasMany relationship to AuthorBook.
Book has a hasMany relationship to AuthorBook.
AuthorBook has a belongsTo relationship with Author and Book, and additionally has a url field.
This solution works, but for some reason the fact that Book is not directly connected to Author is bothering me. Is there any way to achieve this same effect while also cutting the AuthorBook model out of the picture?
(Also, I realize I can have them directly related while keeping AuthorBook, but that seems ugly and also redundant.)
(Also, I realize that I would still have an author_book SQL table. This does not bother me in the slightest, I think it's impossible to do without anyway.)
Thank you for your time! And please don't flame me!!!
Yes, you can model the AuthorBook relation (or the 'edge' as you envision it).
class Author extends AppModel {
...
$hasAndBelongsToMany = array('Book', array('with' => 'AuthorBook'));
....
}
The "with" habtm option:
Defines the name of the model for the join table. By default CakePHP will auto-create a model for you. Using the example above it would be called RecipesTag. By using this key you can override this default name. The join table model can be used just like any "regular" model to access the join table directly.
This is the equivalent of RoR's "through", depicted quite nicely in this illustration
Related
There is a Book table that is always unique with title, edition, and author.
And I want all bookstores to add their books, but different bookstores can have the same book with different pricing. So I come up with this table design.
So when one bookstore tries to add a book and the book is already been added by another bookstore the current bookstore should have to just fill in the pricing detail, not including the book detail.
The problem with this is, what if the book detail already been added has some missing or incorrect info? in this case, the current bookstore can flag and moderators or admins can fix it.
Is there any better way to achieve this? I don't comfortable with this design logic at all.
Your design makes sense. You want to keep the "static" information in 1 table, and link "dynamic" information like you did.
Your other question is related to data integrity. You can put "not null" conditions on fields to ensure all fields are filed, but garbage entries are always possible. This is a universal problem.
Potential solutions to mitigate this:
any and all data that can be selected instead of typed in should be linked via another table. Ex:
BookGenre
bookgenreid PK
genre CHAR
Book
bookid PK
genre FK, BookGenre.bookgenreid
...
So you store all possible genres in a separate table, so your users cannot invent new genres or mistype values. Same for authors, countries, ... This makes it easier to build queries as well and avoid things like [ SciFi, Science Fiction, Sciance fiction, ... ]
not everyone should be able to enter new books in the system. Ex. when I worked at a wholesale distributor, only a select group employees could create new products in the database, and they had established a convention on how to do it. They worked closely with purchasing and receiving. You will need to dedicate "data administrators".
So try to control as much as you can in the database and - or the application. Avoid free text fields as much as possible, as users will always think of new ways to mess it up. Ex. at work currently we have a HUGE project to standardise addresses between unlinked systems. It is a enormous undertaking, which involves AI. All this only because no 2 persons enter addresses exactly the same.
I usually find everything I need, but there is first time for everything.. :D
I am trying to create a conceptual data model and I dont know how to properly show M:N relationship, which by default should not be included, but still you can assign verbs and directions of abstract entities. So let's say we have "Projects" and we have "Project roles", how do I properly show relationships? Can I have 2 arrows as showed in the picture or do I have to add join table and ?? I can't wrap my head around this..
Thank you so much in advance :)
enter image description here
A conceptual data (or information) model can be created with a suitable modeling language, such as ER diagrams or UML class diagrams. Both languages have a concept and a visual notation for many-to-many associations (or relationship types). Simply follow their definitions. Since there is no standard for ER diagrams, it's easier/preferable to go with UML.
For showing a many-to-many association between two classes (representing entity types), you draw a connection line and annotate it with an asterisk ("*") at both ends.
Notice that a join table is a database implementation, and not a modeling concept.
I've been asked by my teacher to make the ER diagram of a certain library. Here is a very simple and not complete ER diagram only to illustrate my point:
Searching the library's website I found exactly the attributes I need for the customer, for the copies the book etc. However, the book is not the only thing provided by the library. The library provides music-CDs , journals, DVDs and many more leading to 20 different kinds of items in total.
One very ugly solution would be to create a different entity for all these items and connect each one of them with the copy entity. And this seems unavoidable since each item type has different attributes. A book for example has ISBN and a journal the ISSN. Looking at all the attributes of each item the only thing they all have in common is a title.
Is there a better way to do the ER diagram?
unfortunately no, he is asking for an academic solution and the way to represent the mini-world in er is 1 entity type per object. this is my vision to ER diagrams in its simplest academic form.
if you continue to sum entity types together, your entire mini world will be one entity type.
I'm in the process of structuring a databasemodel for my new project. For all the entities in my model (which is a cms, and the entities as such f.ex: page, content, menu, template and a bunch of others) they all have in common the same attributes on dates and names.
More specifically each entity contains the following for the dates: IsCreated, IsValidFrom, IsPublished, IsDeleted, IsEdited and IsExpired, and for names: CreatedByNameId, ValidFromByNameId, PublishedByNameId and so on...
I'm going to use EF5 for mapping to objects.
The question is as simple: What is the best way to structure this: Having all the fields in every table (which I am not obliged to...) or to have two separate tables which the other can relate to...?
Thanks in advance /Finn.
First of all - give this a read - http://www.agiledata.org/essays/mappingObjects.html
You really need to think about your queries/access paths. There are many tradeoffs between different implementations.
In reply to your example though,
Given the following setup:
COMMON
ValidFromByNameId
SPECIFIC1
FieldA
SPECIFIC2
FieldB
Querying by the COMMON attributes is easy but you'll have to work some magic when pulling up the subclasses (unless EF5 does it for you)
If the primary questions you're asking are about specific1 and specific2 then perhaps this isn't the right model. having the COMMON table doesn't really buy you much necessary as it will introduce a join to load any Specific1 object. In this case, i'd probably just have duplicate columns.
This answer is intentionally partial as a full answer is better handled by the numerous articles and blogs already out there. Search for "mapping object hierarchies to databases"
I have an app in which Users belong to many Categories. So I have a Users table, Categories and Users2Categories table. The Users2Categories table consists of a user_id and category_id. So I guess the question is: do I create a model for Users2Categories? Ultimately, I would like to be able to "find" User objects and have their respective categories attached.
Also, can I define this relationship via the baking console?
Read about HABTM in the cookbook. Rename 'Users2Categories' table to 'categories_users'.
You can bake the models from the console but you must have the correct tables first (see above).
HABTM is definitely the way to go.
Cake will handle the join table for you, provided you adhere to the Cake conventions.
Read the section in the Book linked to by bancer, then read it again. Then read this: http://mrphp.com.au/code/working-habtm-form-data-cakephp which will help you with realworld implementation.
So, you asked two questions and got some good information, but the answers are pretty straightforward:
do I create a model for Users2Categories?
You can, but I wouldn't. Cake will create a model for the join at runtime. Since this model/table exists solely to facilitate the join (i.e. it has no properties or methods of its own), just let Cake do that work for you. As stated by #bancer, though, you will need to name the table according to Cake's convention.
Also, can I define this relationship via the baking console?
No. You can create the model skeleton, but that won't include the definition of any associations. AFAIK, there's no way to do that. Bake the skeleton, flesh it out with associations, etc.
I could not have been more wrong. See comments. Thanks for the education, #bancer and #beporter.