Complex Model Structure in Cakephp - cakephp

I am creating a site that allows users to add a number of various items to their pages. These items can be very different from each other, such as text, images, numbers, etc. To handle this, I have one table that stores one entry for each item. The table has an id, the location of the item on the page, and the type of the item. I then have one table for each type of item which holds the more specific information about that item.
What I want to do is to set up an association so that when the page loads, it grabs the items from the main table in order - which is simple - and then also grabs the associated information from the proper table of specific information.
An example main_table could be:
id | location | type
1 | 1 | text
2 | 2 | image
3 | 3 | plot
4 | 4 | question
The table for text items may look like:
id | text |
1 | aaa |
2 | bbb |
The table for plots may look like:
id | type | datasets |
1 | bar | 3
2 | scatter | 2
So, can I set up an association where the main_data model pulls in the one associated file from the proper table? I could set up a separate model that selected the table for the specific information based on a passed in variable and set the source, but I am not sure how you would pass the variable with the type information to the model, nor am I sure if I am approaching this properly?
Thanks
PS
I had thought of the obvious - to combine the items into one table and simply have empty fields for everything not related to that item for each entry. So a text entry would still have columns for plot stuff, but they wouldn't be filled, etc. However, I wanted to be less wasteful of space - unless everyone thinks it would work better.

Sorry I don't have the reputation to comment for clarification, but this is what I made of your question. I think you're overthinking it...
The one thing that sticks out about your question, is that things are going to get very messy with the way you're approaching it.
In my opinion the best way to handle this is to give each item type it's own table then associations in the model definitions.
This is how your tables will look like, remember CakePHP tables need to be plural and user_id is deliberately titled as such.
Users
id | username
1 | example
Questions
id | user_id | text
1 | 1 | this is a question
Plots
id | user_id | text
1 | 1 | this is plot
This in your app/Model folder you will need files called User.php & Question.php & Plot.php (singular naming convention) that should look something like this
User.php
<?php
public $hasMany = array(
'Question',
'Plot'
);
?>
Question.php
<?php
public $belongsTo = 'User';
?>
Plot.php
<?php
public $belongsTo = 'User';
?>
Once you have set up the above, you will be able to easily access Plots and Questions in your views, I've provided below a snippet of a potential users controller and expected usage you can expect to use... learn to use debug() in CakePHP it's fantastic.
Controller/UsersController.php
<?php
...
public function index() {
$this->set('users', $this->paginate());
}
...
?>
View/Users/index.ctp
<div>
<?php
foreach ($users as $user):
debug($user);
echo $user['Question']['text'];
echo $user['Plot']['text'];
endforeach;
unset($user);
?>
</div>
After reading your question again, you mention "order" and "location". You can handle this by adding a column for "date_created" and "page_position" to each different table. I still feel like you overcomplicated your solution, and I hope I didn't miss something.

Related

CakePHP 2.9 converting CSV string to HABTM data

I am trying to convert a large database (~3m rows) that contains the following data set titled "Posts":
+-------|---------------|-----------------------+
| id | name | tags |
|-------|---------------------------------------|
| 1 | post title | tag_a, tag_b |
| 2 | another title | tag_b, tag_e, tag_j |
+-------|---------------|-----------------------+
I also have an empty "tags" table with the headings id, title and a "posts_tags" table with the headings id, post_id, tag_id
Post <-- Habtm --> Tag
My question:
I would like to know the most efficient (preferred but not required cake way) of populating the "tags" table and the "posts_tags" habtm table while keeping the tags table free from duplicates?
Many Thanks SO Team!
I have no time to write code right now.
You could get all posts (I recommend you paginate your result) and for each post, you get its tags and explode it by comma.
Then you create an HABTM array data using the tags and the currently post, and finally you save your data.

Assign rows to category in Openrefine

I have a dataset like this, and I'm looking for a way to add a category, based on what kind of product I have.
Can I search for Apple + Orange and assign them to a category named Fruits, and similar with Milk + Wine and assign them to another category, named Drinks?
| Item | Category |
|-------|----------|
| Apple | | <-- Fruits
| Orange| | <-- Fruits
| Milk | | <-- Drinks
| Wine | | <-- Drinks
Or maybe a simpler method: find any rows containing Milk and assign them to category Drinks?
This is something you can do without code.
Filter or facet in the Item field for each value
Create a facet on the Category field
Click the edit button next to the blank value in the Category facet and type with the category you want to add.
Edit your Item facet or filter to move to the next category and repeat this process until you have categorized all yours items.
As magdmartin says you can do this using facets and edits - the solution he describes is probably the simplest approach and least error prone. However, if you prefer to do in a single step you can use GREL to test the content of the Item cell and then set the value in the Category cell dependent on the content of the Item cell.
with(cells["Item"].value.toLowercase(),w,if(or(w=="orange",w=="apple"),"Fruits",if(or(w=="milk",w=="wine"),"Drinks","")))
This is the same approach as given by Ettore Rizza above but in GREL rather than Jython.
magdmartin and Owen Stephens give good answers. Another simple way using GREL:
From the options dropdown for your 'Item' choose Edit column > Add column based on this column...
New column name 'Category' and in the expression set:
value.replace("Apple","Fruit").replace("Orange","Fruit").replace("Milk","Drink").replace("Wine","Drink")
You could keep adding .replace("whatever food","whatever category") ad nauseum

cakePHP- retrieving from database. Models Associations & database

I feel pretty darn dumb for asking this question but I'm baffled, probably because I'm slightly intimidated with cakePHP(new to it, and not very comfortable),but its merits are practically forcing me to use it. So please if you could help, I appreciate it :
My problem is with understanding how Model association works. After going through all the section about associations here I am still struggling and actually am not quite sure whether either my database design is flawed, or the associations between the models, are wrong.
Here it is : I have 3 Models, which are :
Donor, BloodGroup, DonorType
To start with, I am not completely sure if I should create a model for every table in the db.
My tables look like this :
+-------donors-------+
| donor_id (pk) |
| name |
| surname |
| donor_type_id (fk) |
| blood_group_id (fk)|
| |
+--------------------+
+----donor_types-----+
| type_id (pk) |
| type |
| |
+--------------------+
+----blood_groups----+
| blood_group_id(pk) |
| group |
| |
+--------------------+
Donor Model
class Donor extends AppModel{
public $hasOne = array(
'BloodGroup'=> array(
'className' => 'BloodGroup'
),
'DonorType' => array(
'className' => 'DonorType'
)
);
According to the tables in the database, above is how the relationships can be described. I am already using the association to register a new donor with values retrieved from the blood group table/model, using this code in my controller:
$this->set('bloodGroups', $this->Donor->BloodGroup->find('list',
array('fields' => array(
'BloodGroup.blood_group_id','BloodGroup.blood_group'
)
)
));
Therefore I think the association is correct. However, now I want to display the stored users with the relevant details, but an sql error is being generated :
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'BloodGroup.donor_id' in 'on clause'
This is ofcourse because there is no 'donor_id' as a fk inside the BloodGroup table, by actually there is a blood_group_id as a fk inside the donor table.
So what is the solution to this? Is the db design flawed or is there a way I can redefine the association within cake ?
There appear to be 2 things wrong with your setup.
You are not following Cake database conventions. Unless your hands are tied (e.g. external datasource you have no control over), your primary key should always be called id, not table_name_id. Cake always looks for id keys by default. If you have no choice, you can set a custom primary key by setting the primaryKey property in your model.
By looking at your tables, you seem to be mixing up hasOne with belongsTo. Even though in plain English it sounds logical that a donor has one blood group, from a database standpoint, the donor belongs to a certain blood group. The manual has some notes that help you pick the right one:
hasOne: the other model contains the foreign key.
belongsTo: the current model contains the foreign key.
This is also illustrated with some examples in the documentation (see links above). The latter one is true in your case, so your model should eventually look like this:
class Donor extends AppModel {
public $belongsTo = array(
'BloodGroup',
'DonorType'
);
}

Django Database Design: Many-to-Many, Foreign Key, or neither?

A noob question. I'm putting together my first database and have the following design problem: I have a class which defines a book (e.g. it's title) and a class which defines a page (e.g. it's design).
The table for the class book would look so:
Title | PAGE1 | PAGE2 | PAGE3
Book-One | SAMPLE1-UUID | SAMPLE2-UUID | SAMPLE3-UUID
Book-Two | SAMPLE4-UUID | SAMPLE5-UUID | SAMPLE6-UUID
The table for the class page:
UUID | FONT | CONTENTS etc.
SAMPLE1-UUID | Times | Example
SAMPLE2-UUID | Arial | Example Two
SAMPLE3-UUID | Verdena | Example Three
Now, as each page is unique and can't be re-used in another book, I can't use a many-to-many relationship for Pages. I could use Foreign-Key to link the two tables, i.e. link SAMPLE1-UUID of the Books Table with the SAMPLE1-UUID of the Pages Table. This has the advantage of not creating the same entry twice.
However, I don't like the idea of having a fixed amount of rows for my pages. In the above example for the class Book, I'd have to define a certain set of Pages, like PAGE1, PAGE2, PAGE3, PAGE4, ... PAGE99. Ideally, all I need is a flexible list of pages for my book class, like so:
Name | Pages
Book-One | "SAMPLE1-UUID, SAMPLE2-UUID"
Book-Two | "SAMPLE4-UUID, SAMPLE5-UUID, SAMPLE6-UUID"
Pages would be a simple CharField and its contents would be a list. But then I have the problem that the two tables are not linked anymore and that I'd have to create each entry twice (i.e. I would have to enter SAMPLE1-UUID in both the pages and books table).
Is there another way to design this database? Thanks for any suggestion!
I'll suggest you don't have the pages as columns:
The table for the class book would look so with book only information:
Title | ISBN
Book-One | XXXXXXXXXXXX
Book-Two | YYYYYYYYYYYY
The table for the class page:
BOOKID |PAGE_NUM | FONT | CONTENTS
1 |1 | Times | Example
1 |2 | Arial | Example Two
2 |1 | Verdena | Example Three
Your class design would look something like:
class Book(models.Model):
title = models.CharField(max_length=100)
isbn = models.CharField(max_length=100)
class Page(models.Model):
book = models.ForeignKey(Book)
page_num = models.IntegerField()
font = models.charField(max_length=100)
content = models.TextField()
You can go ahead and have contraints so that a book and page_num does not repeat for instance but this can be a good start.
I would do it like this:
class Book(models.Model):
name=models.CharField(max_length=....)
class Page(models.Model):
book=models.ForeignKey(Book)
number=models.PositiveIntegerField()
I don't understand your book table example: Do you want a column for page1 and an other column for page2? That looks very strange.
You've misunderstood how a foreign key works. It's not a "fixed amount of rows" - just the opposite, in fact.
As guettli shows in his answer, a ForeignKey field is a one-to-many relationship, defined on the "many" side. That is, with the ForeignKey defined on Page pointing at Book, each Page has one Book, but a Book has as many Pages as you like.
So, using the Django ORM, if you have a book object and you want to get all its pages, you just do my_book.page_set.all().

database structure for static pages

please help me on this one:)
Most of the time I am creating static pages like Contact Us, About Us, FAQs etc
If I want to store some dynamic items in the page, how will my table look like?
Let's say for the FAQ page, I am to store the question and the answer on the database. For the contact page, I will store emails and and some other contact information. Does that mean I have to create a separate table for each?
Often times I've seen people create a table for Meta information. It resembles a key => value relationship, where the first field of a row is the name and the second is the value. So if you were to manage your global contact information in the database, you may have the following rows:
Meta-Data Table
Meta ID | MetaTitle | Meta Value
---------------------------------------------------------
01 | email_address | some.guy#somedomain.com
02 | phone_number | 1.234.567.8901
03 | num_subscribers | 2312
04 | page_styles | background-color:#333333;color:#ffffff
As for your frequently asked questions, you could do that as a table, if you like:
Questions
Question ID | Question | Answer
-------------------------------------------
01 | How tall are you? | Not nearly tall enough.
Or you could simply create a generic 'pages' table:
Pages
Page ID | Page Title | Page Content
--------------------------------------------
01 | FAQs | How tall are you?
| | Not nearly tall enough.
--------------------------------------------
02 | Contact Us | Phone: 1.234.567.8901
| | Email: some.guy#somedomain.com
Based on the information provided, yes - it's quite likely you'll need separate tables.
Tables are just groupings of similar information, and email doesn't relate to questions & answers. With more information about what you're looking to do, and any business rules around it, we can help you with structure if you'd like.
You could just have 1 table which has a page id column and a page content column. The page id being different for each page you want to store in the database. And the page content column can be a text field which contains the HTML you want to display on that page. Then on each page you would query the database passing the parameter for the page content you wanted to display.

Resources