From my experience if no $db is specified when creating a new class all the data for that page type goes into the Page && SiteTree tables.
I personally find this behaviour quite messy and unorganised and would like anything defined as it's own thing to have it's own table.
Is there any way to explicitly set a new class to have and use its own table regardless if it does or doesn't have any additional fields added via $db?
Is there any way to explicitly set a new class to have and use its own table regardless if it does or doesn't have any additional fields added via $db?
No.
Once a DataObject (which SiteTree is simply a subclass of) contains a $db static, then a table is created of the same name with fields on it comprising those fields you define in $db.
Doing anything differently would be to "break SilverStripe" and how it uses its ORM. If you create a DataList and dump the output of its sql() method, you'll see that queries for Page are JOINed to the SiteTree table. Doing this way is in fact tidier as you can always expect the Title, Content (etc) fields to be in the SiteTree table and anything custom you declare in your Page and Page subclasses, to be in their own respective table(s).
$sql = SiteTree::get()->filter('ClassName', 'Page')->sql();
var_dump($sql);
Related
I'm building a formType to filter products on a collection page. You can set multiple select boxes which makes other auto filled or unnecessary. I want to be able to manipulate the formType based on the data like when using a data_class object. I'm not using data_class because the search isn't a persisted object which is saved to the database. I'm using a GET form.
For example 2 select boxes:
category
productType
When setting a category makes some of the productTypes unnecessary. So i want to not show it.
To do so in the formType I need the data of the request (GET) but I can't find a way to do so.
To retrieve data from the form, you can use $form->getData().
As you're in a GET context, I suspect you can take advantage from FormEvents (take a closer look to POST_SET_DATA event) and get rid of values you don't need.
One other thing I would like to point out, is that you still can use some kind of object that's not persisted to DB, like DTO or whatever.
Forms and entities are not related anyhow, neither in the usage nor in the intentions.
Let's say I have a Setting entity with some fields like IntValue, dateValue, stringValue and some linked entities, like countries (ManyToMany to entity Country), languages (ManyToMany to Language) etc.
Settings are created by users and assigned to specific objects (not important here, but I wanted to clarify).
Now I suddenly need to have UserDefaultSetting, which will be the same, but with additional user field (ManyToOne to User entity).
I tried to extend existing Setting entity class with one more field added. The problem is, as I looked at the schema update SQL, it created new table for the new entity, but without all the tables needed to ORM connections (mostly ManyToMany). Just one table with "scalar" fields.
So previously I've had setting table with int_value, date_value etc. but also setting_country and setting_language tables, linking ManyToMany relations. After creating child entity, Doctrine created only user_default_setting table with int_value, date_value etc. and additionally user_id column, but I can't see any relation/link tables.
I know I should've been do it with abstract base entity class, but at the time I started, I didn't know that and now part of the project is on production (don't look at me like that, I blame the client) and I don't want to change that "base" class now. Can I inherit everything from non-abstract entity class in a way it will work?
UPDATE: everything explained. See Cerad's comment. Thanks!
I'm using Visual Studio 2010 to create a dynamic data site with scaffolding according to: http://www.asp.net/web-forms/videos/aspnet-dynamic-data/your-first-scaffold-and-what-is-dynamic-data
The site displays a SQL table with an "Insert New Item" link, which takes you here:
I have another SQL table which holds some of the information already. I would like to add a function that is called when the user navigates away from the "account" field; the function will query the other SQL table and populate the fields that it already holds for that account.
I'm stuck on where to put the function and how to setup the account field to call it.
It's a couple of years since I did one of these so pardon the details being a bit short.
You can 'override' the default New Item form. In that you can pre-populate the fields with anything you want. I think you have to take care of the Save also, and of setting out the controls on the form and populating them (you've overridden the generated form after all).
Another possibility is to create a partial class which extends the Model class and populates it in a constructor extension (I remember doing various stuff with this technique). There might also be some extension points on the model Context (or whatever its called) which you can tap into - it's pretty flexible as I remember.
What are the benefits of reusing an existing field for a content type?
Alternatively, what are the benefits of making a new field for a new content type?
For example, I have a content type called 'Book Review' with a field labeled 'Summary'. I'd like to create a new content type called 'Movie Review' and also give it a field called 'Summary'.
Benefits of reusing an existing field
One table(in fact 2) less in your database and hence the performance gets better.
Say when you want to display the summaries of all the content(irrespective of content type), reusing the existing fields will make your queries simpler.
When you are using views for the displays you just need to add one fields instead of different fields for each content type. Say you want to display summaries of both Book Review and Movie Review, you can just add both to the content type filters(or) and add the single common field.
When you are overriding the template files, you just need to overwrite one template instead of many.
Benefits of using different(new) fields
If both the fields has to be displayed separately, then you can have more control.
If there are very large number of values in your fields, then instead of querying a single table with 1 lakh entries, you will only need to query a table with 50,000 entries. This might add to your performance(But am not very sure, can be case specific)
My preferred choice
Reuse existing fields when it makes functional sense. For example I generally reuse noderefernces to the parent content type so that it keeps most of my queries simple.
In your user-stories if it doesn't make sense to reuse then better go for the the new fields.
Reusing same field - Let you handle the field at one place. Code handling + theming.
Making a new field - summery is not a good example, since you have a built in text area given by Drupal. Adding an image field with the same preset size for both (movie & book) will give you the ability to show images on each content type and let them look the same if you want (without double work).
We're planning to create a web application where users can build custom "forms," choosing which fields they would like, and how the data in those fields should be represented. Users can then fill out these forms in a DetailsView-like control, thereby creating "documents." The documents can be shown in a DetailsView, or certain fields of several of them can be shown in a GridView. At least, that's the idea.
The problem is that GridView and DetailsView seem to be specifically designed to access Properties on objects that come out of a DataSource. Since we want to have completely arbitrary forms, we can't restrict ourselves to building a class with Properties to represent each field. We have to be able to have any number of dynamically-specified fields on a form.
Is there any way to leverage the existing controls so we don't have to re-implement paging, sorting, and all the other things that GridViews are already set up to do, or will I just have to create my own GridView-like control from scratch?
Edit:
More specifically, the difficulty I am having is in getting inline editing to work on the GridView. For example, let's say that one of the "fields" that is added to a "form" is a calendar field, which should display a date as text in read-only mode, and display a calendar control in edit mode. When the "save" button is clicked, the date selected by the calendar control needs to be saved to the database as the new value for the given field of the given document (i.e. instance of the form). My initial idea was to create a special DataControlField class which, given a form field key, would know how to databind thusly:
FormDocument doc = DataBinder.GetDataItem(cell) as FormDocument;
FormFieldValue fieldValue = doc.FieldValues[FieldKey];
fieldValue.AddReadOnlyControls(cell);
... instead of:
Object dataObject = DataBinder.GetDataItem(cell);
cell.Text = DataBinder.GetPropertyValue(dataItem, FieldKey);
This would probably work for displaying the field values, but if the user tries to edit and save one of the FormDocuments I don't know how I would convince the GridView to do something like this:
doc.FieldValues[FieldKey] = newValue;
Currently, the API for DataControlField uses the ExtractValuesFromCell method to put the property name and value into an IOrderedDictionary. Those values are then applied to the given properties of the objects in the GridView's databound IEnumerable. The problem is, I can't work with properties of an object because in this case the object needs to have a completely arbitrary number of fields.
A GridView can be bound to any object that implements IEnumerable. The advantage of using one of the xDataSource controls is that it can implement paging and sorting for you without any additional code, but you certainly aren't tied to them.
If I understand your question correctly, you do not know the number of columns to display in the GridView until runtime. In that case, I would recommend building an array from your form data and binding the grid to that. You will have to implement paging and sorting yourself.
The DetailsView is not very customizable so you should take a look at the FormView. However, I think you are going to end up dynamically adding controls to whatever container you use.
What you need is totally dynamic GridView. I quess you would have to extend it with the controls ( functionalities ) in your description
Here's what I ended up doing:
I created a new data type that contained a Dictionary of answers, indexed by Field ID.
I created a new type of DataControlField with a FieldId property, which retrieves the proper answer value for that FieldId from the Dictionary mentioned above.
I added data type and data keys properties to this custom DataControlField and overrode the ExtractValuesFromCell method so that it could create a new instance of the answer class and add those values to a Dictionary, which was stored under the property name by which that dictionary would be found in the new data type mentioned in step 1.
I used my own GridView class, used the .NET Reflector to see how the normal GridView calls the ExtractValuesFromCell method, and then changed that so that it would pass the same Dictionary object in to each DataControlField. This way, each field could add to the same Dictionary, rather than replacing the Dictionary that the last one had added under the same property name.
I used a DataFieldGenerator to generate the one of my custom DataControlFields for every field associated with a given form, and I told the GridView to use that DataFieldGenerator to auto-generate its fields.
I set up my ObjectDataSource so that it would know how to save all the answer values from an object of the type mentioned in step 1.
It was tricky, but worthwhile.