One table for uploads for multiple resources in CakePHP - cakephp

I have CakePHP app in which I'd like to attach gallery to multiple resources. Let's say I've got artists, each one has own gallery. I've got articles, every article has some images attached to it and so on. Now I set up tables like this:
Artists hasMany Artistimages, fields in artistimages table are: id, artist_id, filename, filetype, filesize etc.
Articles hasMany Articleimages, fields in articleimages table are: id, article_id, filename, filetype, filesize etc.
...but this is not how it should be, I think.
Is there possibility to have one table called for example uploads which will contain all images with foreign key pointing to resource its reffering to? How to tell CakePHP which image is coming from which resource?

I'd recommend using the Polymorphic Behavior. I often do this for a Binary model which covers images, documents, etc. These represent the physical files that can be associated with any number of models (photos, applicants, etc.).
The gist of a polymorphic relationship is that the table has 2 additional fields. One field that indicates the name of the model being associated (e.g. Photo, Applicant, etc.) and another for the foreign key value (i.e. the id field in the photos table, for example).

If this was me, I would have an images table, then I would have the Artist and Article hasAndBelongsToMany to Image.
Your HABTM would then have a two join tables artists_images and articles_images, then with any luck, Cake will write into these join tables the relationships between each. So you should end up with the correct things associated with the correct images.
By using the HABTM, you can even have one image associated with an Article and Artist, and the same image associated more than once if you need to.
Hope this makes sense, there is more info on HABTM in the book, http://book.cakephp.org/view/83/hasAndBelongsToMany-HABTM

For all of you looking for working solution using polymorphic behavior and MeioUpload, check out this. I'm using it right now and it seems to work fine.

Related

a user bookmark system database design

my user need to bookmark the articles, videos, pictures posted by the others.
now I have a user table, an article table, a video table.
and I come up with two way to store the bookmark data..
first, I can create three one-to-many table.
the second way is only create a table and add a category column on it..
with the first approach, I can store foreign keys to associate with the articles and video table. witch is easier for the orm system
and the second way only need a table, but can't store the relationship..
so. which one should I choose,or Is better???
the third way is something like.
I have worked with tables that employ both types of relationships. For ease of use, I do not prefer the second method. There is another method you may wish to try, which would be (sorry, no picture):
USER
UserId
USER_BOOKMARK
UserBookmarkId
UserId
BookmarkAssetId
USER_BOOKMARK_ASSET
UserBookmarkAssetId
UserBookmarkId
AssetType (Title, href, image, caption, tooltip, etc)
AssetStringValue (nullable)
AssetNumberValue(nullable)
AssetByteArray (nullable)
You would get a bookmark like:
SELECT * AS UserBookmarkLinks
FROM USER_BOOKMARKS ub
INNER JOIN USER_BOOKMARK_ASSETS uba
ON ub.UserBookmarkId = uba.UserBookmarkId
WHERE ub.UserId = 12345
AND uba.AssetType = "Link"
From there you may have BOOKMARK_TYPE_ASSETS which tells you what assets are included with each type and which field in USER_BOOKMARK_ASSETS it uses. This is a little more involved with tables, but a lot closer to normalized.

Designing a database with similar, but different Models

I have a system whereby you can create documents. You select the document type to create and a form is displayed. Data is then added to the form, and the document can be generated. In Laravel things are done via Models. I am creating a new Model for each document but I don't think this is the best way. An example of my database :
So at the heart of it are projects. I create a new project; I can now create documents for this project. When I select project brief from a select box, a form is displayed whereby I can input :
Project roles
Project Data
Deliverables
Budget
It's three text fields and a standard input field. If I select reporting doc from the select menu, I have to input the data for this document (which is a couple of normal inputs, a couple of text fields, and a date). Although they are both documents, they expect different data (which is why I have created a Model for each document).
The problems: As seen in the diagram, I want to allow supporting documents to be uploaded alongside a document which is generated. I have a doc_upload table for this. So a document can have one or more doc_uploads.
Going back to the MVC structure, in my DocUpload model I can't say that DocUpload belongs to both ProjectBriefDoc and ProjectReportingDoc because it can only belong to one Model. So not only am I going to create a new model for every single document, I will have to create a new Upload model for each document as well. As more documents are added, I can see this becoming a nightmare to manage.
I am after a more generic Model which can handle different types of documents. My question relates to the different types of data I need to capture for each document, and how I can fit this into my design.
I have a design that can work, but I think it is a bad idea. I am looking for advice to improve this design, taking into account that each document requires different input, and each document will need to allow for file uploads.
You don't need to have a table/Model for each document type you'll create.
A more flexible approach would be to have a project_documents table, where you'll have a project_id and some data related to it, and then a doc_uploads related to the project_documents table.
This way a project can have as many documents your business will ever need and each document can have as many files as it needs.
You could try something like that:
If you still want to keep both tables, your doc_upload table in your example can have two foreign keys and two belongsTo() Laravel Model declarations without conflicts (it's not a marriage, it's an open relationship).
Or you could use Polymorphic Relations to do the same thing, but it's an anti-pattern of Database Design (because it'll not ensure data integrity on the database level).
For a good reference about Database Design, google for "Bill Karwin" and "SQL Antipatterns".
This guy has a very good Slideshare presentation and a book written about this topic - he used to be an active SO user as well.
ok.
I have a suggestion..you don't have to have such a tight coupling on the doc_upload references. You can treat this actually as a stand alone table in your model that is not pegged to a single entity.. You can still use the ORM to CRUD your way through and manage this table..
What I would do is keep the doc_upload table and use it for all up_load references for all documents no matter what table model the document resides in and have the following fields in the doc_upload table
documenttype (which can be the object name the target document object)
documentid_fk (this is now the generic key to a single row in the appropriate document type table(s)
So given a document in a given table.. (you can derive the documenttype based on the model object) and you know the id of the document itself because you just pulled it from the db context.. should be able to pull all related documents in the doc_upload table that match those two values.
You may be able to use reflection in your model to know what Entity (doc type ) you are in.. and the key is just the key.. so you should be able.
You will still have to create a new model Entity for each flavor of project document you wish to have.. but that may not be too difficult if the rate of change is small..
You should be able to write a minimum amount of code to e pull all related uploaded documents into your app..
You may use inheritance by zero-or-one relation in data model design.
IMO having an abstract entity(table) called project-document containing shared properties of all documents, will serve you.
project-brief and project-report and other types of documents will be children of project-document table, having a zero-or-one relation. primary key of project-document will be foreign key and primary key of the children.
Now having one-to-many relation between project-document and doc-upload will solve the problem.
I also suggest adding a unique constraint {project_id, doc_type} inside project-document for cardinal check (if necessary)
As other answers are sort of alluding to, you probably don't want to have a different Model for different documents, but rather a single Model for "document" with different views on it for your different processes. Laravel seems to have a good "templating" system for implementing views:
http://laravel.com/docs/5.1/blade
http://daylerees.com/codebright-blade/

Database Architecture: Multiple Type Relations

I'm building a Laravel application that has "listings". These listings can be things like boats, planes, and automobiles; each with their own specific fields.
I will also have an images table that should relate to each type of listing and a users table that needs to map to each type of listing. I'm trying to determine the best way to map each listing type back to images and users.
One way I've thought of doing this was having separate boats, planes and automobiles tables with their specific fields and then having specific boat_images plane_images and automobile_images tables to map to each respective type. But then relating each type to a user would be a bit tricky.
I don't think one giant listing table with all fields I'd ever use through these 3 (which could grow in size later) would make sense --- and I also don't believe having a general metadata field that has a JSON object full of specifications for each listing would work well either when I want to have a searchable database.
I know of pivot tables, but I'm trying to grasp the overall architecture here. Any help would be greatly appreciated. Thanks!
You could have a listings table, holding only id and name. Boats, planes, automobiles and others should be a subset table.
Each table will have its own entity. And the Listing entity will have multiple hasMany relationships with its subset tables. These relationships will be named like boats(), planes(), etc. Each subset listing entity will hold a single belongsTo relationship.
Using these subset tables should also help to compartmentalize form validation.
You can have a single images table and use a polymorphic relationship towards the listings table. This one is a huge savior.

Implementing tag clouds with CakePHP

I did a little research on tag clouds, and I ended up choosing a schema similar to the Wordpress one seen in this page: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html
Currently, the tables that I have created is: Posts, PostsTagMaps, PostsTags
1) Would I need to create a table for PostsTagMaps even if I don't plan on using a controller?
2) A Post hasMany PostTagMaps. I'm not sure where should I be defining this relationship. I think it should be the Post model, but then I would have to join the PostsTags table to PostTagsMaps then join it to Posts, so I wanted to ask for some advice.
The easy solution is to follow Cake conventions (which will look very similar to the solution you linked to). You'll have three tables:
posts, tags, posts_tags
Then your Post model HABTM Tag model. The join table will automatically be used by Cake to save and retrieve the information. Check the book for more information on setting up your schema.
Cake is flexible enough where you can do it however you want, but if it's a basic sort of posts-tags relationship, the convention method is the way to go.
If you want to use a custom model/table like PostsTagMaps, then do this by using the 'with' key in your HABTM relationship definition. The 'with' key tells Cake to use a specific model (and therefore a specific table) instead of an automatically generated version. In this case, your tag model sounds like it's PostsTags and your HABTM table is PostsTagMaps, so the 'with' key on Post HABTM PostsTag would be PostsTagMap.

Denormalization of database tables for Lucene indexing

I am just starting up with Lucene, and I'm trying to index a database so I can perform searches on the content. There are 3 tables that I am interested in indexing:
1. Image table - this is a table where each entry represents an image. Each image has an unique ID and some other info (title, description, etc).
2. People table - this is a table where each entry represent a person. Each person has a unique ID and other info like (name, address, company, etc)
3. Credited table - this table has 3 fields (image, person, and credit type). It's purpose is to associate some people to a image as the credits for that image. Each image can have multiple credited people (there's the director, photographer, props artist, etc). Also, a person is credited in multiple images.
I'm trying to index these tables so I can perform some searching using Lucene but as I've read, I need to flatten the structure.
The first solution the came to me would be to create Lucene documents for each combination of Image/Credited Person. I'm afraid this will create a lot of duplicate content in the index (all the details of an image/person would have to be duplicated in each Document for each person that worked on the image).
Is there anybody experienced with Lucene that can help me with this? I know there is no generic solution to denormalization, that is why I provided a more specific example.
Thank you, and I will gladly provide more info on the database is anybody needs
PS: Unfortunately, there is no way for me to change the structure of the database (it belongs to the client). I have to work with what I have.
You could create a Document for each person with all the associated images' descriptions concatenated (either appended to the person info or in a separate Field).
Or, you could create a minimal Document for each person, create a Document for each image, puts the creators' names and credit info in a separate field of the image Document and link them by putting the person ID (or person Document id) a third, non-indexed field. (Lucene is geared toward flat document indexing, not relational data, but relations can be defined manually.)
This is really a matter of what you want to search for, images or persons, and whether each contains enough keywords for search to function. Try several options, see if they work well enough and don't exceed the available space.
The credit table will probably not be a good candidate for Document construction, though.

Resources