Bind a NSSet representing a to-many relationship to the selection of a NSArrayController - cocoa

Here's the scenario. There are two CoreData model objects, A and B, and the relationship between them is that A has-many B, represented by the property setOfBs. I'd like to display two tables, one listing all the As (Table 1), another listing all the Bs (Table 2). As the user selects items in Table 1, the selection in Table 2 changes to reflect the value of setOfBs of the A selected in Table 1. The content of the table doesn't change, only the selection changes. And if the selection in Table 1 changes, it would change the setOfBs to reflect that.
Can this be accomplished using bindings? Or would custom logic be required?

I believe you will have to write additional logic to get this approach to work. Here's why: The selection bindings for NSArrayControllers (and all the UI objects that bind to them) are based on selection indexes but when you have an object of type A, it vends a set of B objects. Assuming you have an array controller for As and an array controller for Bs, you need a way to get from those objects to their indexes in the array of Bs in order to set the selection of the array controller for B. This isn't hard code to write, but I don't believe you'll be able to do this with bindings alone.
That said, as you speculated in your comment, this doesn't seem like a good way to edit this relationship. In the common case, TableView selection is UI state, and not model state. If you build a UI like you describe, UI state and model state become the same thing. I'm not saying it's impossible, or inherently bad, but it's not really a "standard" way to do this sort of thing. One common pattern looks like this:
Even an approach like this will require additional logic, because there appears to not be a way (out of the box) to bind to "All Bs not in the selected A's setOfBs" without writing code. Again, not difficult code to write, but it's not clear to me that this can be done with bindings alone. I could be wrong, but that's my reading of the situation.

Related

Dynamic NSCombobox

I'm creating an application in which I have several entities and now I need to filter the content of third combobox dynamically. I explain myself better. I have 3 combobox (building, floor and department), I would like first to show me all the buildings included, but the second should show only selected before the plans for the building, the last I should be select only the departments of the building and the plan you choose. How can I do this? To simplify attaching some photos.
You simply drill down with predicates, if you use single fetch requests to Core Data.
However, your relationships are not set up correctly. For example, there is an edificio attribute in Particelle. If it refers to an building, it should be a relationship to a Edifici object, not some kind of foreign key. There are no foreign keys in Core Data, just relationships.
If you do this, everything becomes much easier by using a NSFetchedResultsController. You can now simply traverse the object graph without any specific fetching.
The scheme could be something like this (maybe need to change the order):
Anno <--->> Particella <---->> Edificio <---->> AreaRischio
Now you can simply tell the fetched results controller to start fetching all Anno entities. Then you drill down with simple dot notation:
NSSet *listForNextTable = selectedAnnoObject.particelle;
and further with
NSSet *listForNextTable = selectedParticellaObject.edifici;
etc. You see, it gets really simple.

Correct MVC design for Symfony/Propel?

If making things work is only requirement, we can put all controlling login and DB handling logic even in the views & it will work. However this is not a right approach for reusable design.
Before I ask my real design question, below is my current understanding about separation of responsibilities in terms of model.
All Database related code, even db related logic, should go in models.
For a table, say 'my_tab', propel generate 4 classes, out of which only 2 classes 'MyTab.php' and 'MyTabPeer.php' should be edited.
MyTabPeer.php must only have data fetching.
Any logic, if required to fetch data, should go in 'MyTab.php'
This is simple and I hope it is correct, if not, please correct me.
Now, I have a special condition. I've 4 tables, say a, b, c, d. For that, propel generated 8 editable classes (excluding base*.php)
A.php APeer.php B.php BPeer.php
C.php CPeer.php D.php DPeer.php
One page of my application, shows Mailbox (say). Mailbox is not a table in database but it gets its data from complex join query between above 4 tables along with lot of calculation/conditions.
I generated that query, fetch data from it and displayed it. Mailbox is running as expected. However I did it in my controller (action class), which I know is not a right place for that.
My question is, where should I put that code? Possible options:
Controller, I think, is not a right place for DB logic/fetch.
I've 8 model classed however data do not belong to any one of them but as combination of them all.
A separate helper/lib, but I know I'll never reuse that code as its unique page of the site.
Anywhere else?
Please suggest if I'm wrong but I guess I should put it in models as it is fetching data. Since A is primary table, I probably should put code in A.php and APeer.php. If that is correct place, next question is, What should go in A.php & what should go in APeer.php? I've following operations to do:
Some logic to decide what columns, should I select.
As like mailbox, I can show received/sent message. Controller will tell what to show but there are some db logic to set conditions.
Then really fetch data from complex Join query.
Returned data will have all rows but I might need to merge few rows conditionally.
As per my understanding, Point 3 should go in APeer.php and rest in A.php. Is my understanding correct?
You should create separate model class i.e. Mailbox.
Method of this model should do the complex select and return data to your action in controller. This solution will not break MVC approach.

Core data, bindings, NSArrayController and table views - how to generate a view of a core data context

I have a working system that lets me build a database containing instances of various entities , all linked together nicely.
Before I knew I would care, I came across a tutorial on using Core Data and bindings, and it went through a complete case where you get a table showing all the entities of some type with a column for each property. It showed both the UI side and the Data model side - not that I need the data model part at this point. Now, darned if I can find it. This is one of those things that is supposed to be easy, and requires virtually no code, but getting exactly the right connections in UIBuilder is not going to happen if I can't find instructions.
Also, I thought I came across an example of something like a query editor where the user could select which properties to sort on, which to match on, etc. Did I imagine that?
Anyone out there know where I can find such?
Sure, you can do this without code:
Add an array controller to your nib.
Bind or connect an outlet for its managed object context
Set the array controller to Entity mode, fill in the entity name, and select Prepares Content.
Bind your table view columns to array controller's arranged objects, and fill in the key name for the model key.
Regarding the query editor, open up the model, and on the Editor menu click Add Fetch Request.
I found at least a partial answer to the query editor question, in this apple tutorial. Not sure how far it will get me, as I prefer to write code where possible, since then I can leave a trail of comments.

Getting a unique identifier for each element of NSArrayController's content

I'm making a custom view that I want to be bindings/core data compatible and represent a collection of data (a la NSTableView)
Is there any way my view can refer to a specific subset of the elements in the collection (other than the current selection) after a change by the user?
A bit of context:
The view is going to display a number of user-moveable boxes in a 2D space. Each box corresponds to a record in the model. Several can be moved at once, and I can't rely on the delta value being the same for each box (so no adding a delta to each selected object).
I guess I'm looking for something like an id assigned to each element of the content array by NSArrayController, so that the view can associate that id with each box. My first thought was to use the the index in a content array, but this could be messed up by undo/redo. I could subclass NSArrayController and get it to auto-generate an id for each model item, but does cocoa already do something like this already? Feels like I might be missing something.
I should have mentioned that I originally tried keeping each of the content array's elements stored in the view (as Peter suggests), but had them stored as keys in an dictionary.
The objects in the view didn't match the keys in the dictionary, so I assumed this meant that NSArrayController changed the proxy objects it uses to stand for model objects.
However, it turned out that NSDictionary copies its keys, so it seems to be no good for situations where you want to associate a particular instance of an object with another.
NSMapTable is its more flexible cousin, and can be configured not to copy its keys.
Why not just refer to the objects themselves? You can keep them in a set or array, whichever is appropriate.
If you really need an identifier of some sort: What for? What are you going to do with it?

Filter/Sort in the view or in the model?

Having a list of data object and something visual to represent each, where would you code the sorting/filtering logic? Why?
Edit : All the answers so far are good, but I forgot to add another constraint. What if I don't want to reconstruct the view each time?
The answer lies in the data. The model delivers the data. If all the data is in the view, the filtering and sorting can be contained within the view. If the data is chunked, the model must deliver the data and contain some of filtering/sorting (the view may still contain filtering/sorting as well).
The controller should not contain these functions, since it is a routing mechanism and should not have any idea of how to interpret the data.
Depends on the complexity of the sort/filter operation and whether the view control offers those services natively. If the view control offers filtering and it's simply reformatting the in-memory data then leave it in the view. If the sort/filter requires another trip to the data source then keep it all in the controller.
I would put in the sorting and filtering methods in the controller, and call these methods from the view.
Your View should only handle displaying the output. Put any filtering/sorting into your business logic and return it to the view.
I believe the sorting should be something separate. You should not sort in the model because you want to keep it as-is. Basically, a change in the model implies a re render of the view and you probably do not want that (if you want to animate a transition between the pre and post filter states, for example).
What I would suggest is that the model provides the data to create both a list of visual objects for the view and a sorter object. The sorter object would output a render list which would simply be a list of some identifier linked to the visual objects (index in objects list or other). The order in which the IDs appear represents the order of the sorting and any ID not in the render list is hidden. Every time the view receives a render list, it would update it's display.

Resources