CakePHP2 Get Associated Model from DataSource - cakephp

I have an User Model which uses a standard MySQL database and users table and a Movie Model which is a datasource from Rotten Tomatoes. They have a hasAndBelongsToMany relationship and I'm successfully able to write to the join table users_movies which holds the user_id and movie_id (the movie_id is the Rotten Tomatoes id). Works great.
The trouble is retrieving an User's movies. The standard find:
$movies = $this->User->find('all', array('conditions' => array('id' => $user_id)));
only returns the User not the associated Movie(s). I put a die statement in my read method in the DataSource and it's not even reaching the read method. How can I go about retrieving an User's movies?

So Rotten Tomatoes is holding your movies? In that case, of course Rotten Tomatoes wouldn't allow direct SQL access to their database - you'd be accessing it via an API. So Cake definitely won't just be able to join Users to Movies the way it normally would with two tables in the same database.
What you'll have to do is 1) get a list of the user's movie_id's from Cake, and then 2) Call the Rotten Tomatoes API to get a list of movies where their ID is in your list of movie_id's. (That's assuming rotten tomatoes allows such an API call.)
Having a quick look at the API, it looks like their 'movies search' (http://developer.rottentomatoes.com/docs/json/v10/Movies_Search) only allows you to specify plain-text as the search criteria (ie, you can't search based on movie id's). And their 'movie info' method (http://developer.rottentomatoes.com/docs/json/v10/Movie_Info), which does allow you to retrieve a movie by id, only allows you to retrieve one movie at a time.
You could of course loop through your list of movie id's for a given user, and make a separate API call to rotten tomatoes for each one - though I'd imagine that would get VERY slow.
Someone has put in a feature request for retrieving based on a list of multiple id's (http://developer.rottentomatoes.com/forum/read/123940) but until that request gets implemented, you will probably be having a tough time getting anything decent working.

I got it working by making a Model out of my join table between users and movies and getting an user's movies that way. Then I did as you suggested and looped through the user's movie ids making a call to the API and getting each movie. Not sure how elegant it is, but it is working.

Related

NoSql - entity holds an owner ID field vs owner holds list of child ID's

I am currently exploring MongoDB.
I built a notes web app and for now the DB has 2 collections: notes and users.
The user can create, read and update his notes.
I want to create a page called /my-notes that will display all the notes that belong to the connected user.
My question is:
Should the notes model has an ownerId field or the opposite - the user model will have a field of noteIds of type list.
Points I found relevant for the decision making:
noteIds approach:
There is no need to query the notes that hold the desired ownerId (say we have a lot of notes then we will need indexes and search accross the whole notes collection). We just need to find the user by user ID and then get all the notes by their IDs.
In this case there are 2 calls to DB.
The data is ordered by the order of insertion to the notesIds field in the document.
ownerId approach:
We do need to find the notes by their ownerId field across the notes collection which might be more computer "intensive".
We can paginate / sort the data as we want - more control over the data.
Are there any more points you can think of?
As I can conclude this is a question of whether you want less computer intensive DB calls vs more control over the data.
What are the "best practices"?
Thanks,
A similar use case is explained in the documentation. If there is no limit on number of notes a user can have, it might be better to store a userId reference field in notes document.
As you've figured out already, pagination would be easier in the second approach. Also when updating notes, you can simply updateOne({ _id: "note_id", userId: 1 }) instead of checking user's document if the note actually belong to the user.

firebase firestore nosql design for chat app with groups

I am trying to think of a way to design the firestore db in a way that is efficient.
The main issue I am having with is how I should define "groups". Lets say a user is invited to a group chat and so the client needs to retrieve the data for that group chat, should I have a "groups" collection and then find the correct group document? OR, should I have a "groups" property in the user document that has a id to reference the group to retrieve?
In SQL, having a reference in a user's groups table would be the obvious answer, but I am not sure about firestore. I don't want to look through the entire collection of groups just to find the group that the user was newly invited in. Any tips? Also, my front end is in React and I am considering using the onSnapshot method to subscribe to the collection (that seems to be the best way to have real time updates).
What i believe is best for you is this :
First have a collection, suppose you make groups, and inside that every docuent has all the group unique ids,
And inside that for every group, i.e document, you can have a collection which holds all the chats for that group and group related info , like group type, etc etc
Hope it helps. feel free for doubts

Multiple datasources for one model in CakePHP

I have a very interesting problem in relation to CakePHP. I have a client that is currently selling products on eBay, and wants to start selling products on their own website as well. There would, then, be two separate sales avenues: (1) eBay, and (2) website.
However, they do want to have a seamless website experience for their customers. Basically, they want their current eBay sites to be categories within their current website, and their current eBay auction items to be searchable on their website.
A simple CakePHP website would have two tables: products and categories, with the simple table relation of "products belongsTo categories" and "categories hasMany products". How would I then add in the eBay categories and products? Basically, I want the http://site/products/index to return a list of ALL products, both in the products table and on eBay. I want http://site/categories/index to return a list of all defined categories in the categories table plus the categories items are listed in on eBay.
eBay has a very good pretty much real-time request query API, so I've been thinking about an option to do this, but am wondering if there is a better way... I don't think this option would work very well with PaginatorComponent...
Method:
(1) In beforeFind, capture the request parameters and save to a persistent variable
(2) In afterFind, make a request to the eBay API based on the request parameters, then manually add the results to the $results array.
Again, I think this would work for basic find operations, but I'm not sure this would work with pagination because I'm not sure how to deal with, say, a 20 item page limit (i.e. How do I deal with a page 2 when only 18 items from the database were on page 1, and now on page 2 I need to start at 19 instead of 21 from the database?)
Is there a CakePHP syntax that I'm overlooking here, or do I just start working on coding for all of these eventualities?
I'm coding on a CakePHP 2.6.0 platform.
Thanks so much for your help!
One possible approach would be to read all the products from each datasource, sort them in memory and paginate from there. The number of products would of course play a major role here.
A second one, if the number of products does not change too often, would involve a background process to retrieve their ID, and the most essential data, from eBay and write them in the common Product table, flagging the rows created.
Then Paginator can then show your results, but other fast-changing data can be retrieved on-the-fly from eBay for the flagged products while composing the page.

Suitable mechanism to relate json data to database?

So im working on a side project involving the Steam API and I am not sure if this would be a suitable and effective way to do what I want.
Basically I have a User model with an inventory field relating to a certain game. I fetch the Users game inventory when they log-in and store the json result within this single field. I have another model which contains the item schema for every item in the game.
Basically I want to relate the information stored within the database for a particular item(item model) to that items information within the json result(inventory items).
I previously tried to save the inventory in a separate table and created a relation between the user, user-inventory and items in this table however the problem with this was ensuring that the inventory stored in my database was the same as that fetched (exactly identical). Under this scenario I would basically need to delete(multiples may exists of the same item) every inventory item and then insert the inventory items retrieved at login back in.
My question is this. Is this an appropriate solution, bad practice or is there a better way to do what i need?
Thanks
Are you sure that you have to delete all of the inventory items and re-add the new ones? Could you iterate through each of the inventory entries and add/update/delete as needed?
I think that the JSON solution would work. It's probably a matter of preference at this point. I always feel like it's nicer to stay with a traditional relational data structure until you really need to optimize. But I don't see why the json wouldn't work. You can create a utility function on your user model that extracts the item ids and fetches all of the related records.

CakePHP need to know model ID before saving

My situation:
I have a form based on several models linked together.
In background I have a routine for saving images , based on ajax call to a particular controller which uploads the image and displays it on a textarea in realtime.
My problem applies when I have to save the record first time, because the ajax routine needs to know the ID of the record to associate the image , but this will be created only after save() will be called.
Is there a way to obtain a ID before the model saves? or some other workaround
Thanks in advance to everyone
Rudy
I think #RichardAtHome provides a good input on this. I'll just add a third solution you may want to consider:
Use universally unique identifiers (UUID) for that model's primary key. CakePHP offers a way to generate them via the String utility. So what you would do is generate the id when the page loads with String::uuid() and then send it as part of the ajax requests.
A couple of solutions:
Change your workflow, so that the images can only be linked to the main model once the main model has been saved (and has an id).
Don't save your images to the database until the main model has been created. You could store them in a session, or just keep appending fields to the end of the form as the user adds more fields.
Option1:
You could try using UUIDs instead of INTs. That way, you can just use CakePHP to generate an ID: String::uuid();.
After you create it, you can populate an id field that would then make the item save with that id.
I'm not sure I'd rely on it's uniqueness if I were doing banking software or something critical, but - it's something like 1 in a billion chance to be duplicate, and for normal websites/software, it seems like that would suffice.
Option2:
In a lot of our projects, we've found it helpful to have a very simple "create a Thing" page with just a title field, then, once saved, it takes them immediately to the more in-depth "edit" page where they can upload files, save extra data...etc etc. Almost like a pg1, pg2. That way, files, as well as any other dynamic ajax-driven data will have an ID to work with.
Probably not, because the ID will be set by the Database, and not CakePhp, and the id can only be known after the database has auto-incremented the ID field...
Not sure how your flow is, but I guess you can save a dummy/empty row to the database without all the associations when the controller gets the page (when $this->data is empty). You know have an ID to an empty row in the database that is like "12, NULL, NULL, NULL, NULL, NULL, ...". You can then store the ID of that dummy record (or do $this->set("id", $id) to pass it to the view to use in your ajax-calls).
After the POST of your page you can then use the ID to store all other information in dummy row, or delete the dummy row from the database when something fails/user navigates away...

Resources