symfony admin generator table_method - symfony1

When configuring my admin generator I created a table_method for my list view in order to join the correct tables and so on.
However, in my edit post / create post sections I have a rather extensive dropdown that is not joined at the moment. Is there an equivalent to table_method that I can use for these situations to specify the method that should be used for retrieving the record?
Thanks in advance.

You need to modify the respective widget in the form classes. (SomeModelForm.class.php in lib/form/doctrine).
All of the Doctrine widgets accept a "query" option to allow you to pass a Doctrine query to over-ride the default query the form creates, or a "table_method" option that can return a query or a doctrine collection to over-ride the default.
As a reference, see: http://www.symfony-project.org/api/1_4/sfWidgetFormDoctrineChoice
To use query, something along the lines of:
$somedoctrinequery = Doctrine::getTable('ModelName')->createQuery('t')->leftJoin('t.Relation r');
$this->widgetSchema['field_name']->setOption('query', $somedoctrinequery);
Or to use table_method:
$this->widgetSchema['field_name']->setOption('table_method', 'myMethod');

Related

Implementing Select List Lookup ViewModel Attribute

I'm trying to implement a more customisable version of using ViewModel attributes and a Model Enricher to populate viewmodels lists like in this this question and associated blog post.
I would like to be able to specify the method on my select list interface from the Attribute.
Each Select List service I have returns an IEnumerable that I use to make a select list and presently exposes an All interface as the sample does. I can easily use the All method because all interfaces provide that. However I often wish to able to use other methods like the AllTradingCompanies() AllManafacturingCompanies() methods of my select list class to get filtered lists.
It is presently looking like I may have to implement a Custom attribute to map to specific e.g. [AllCompanyList] attributes but that moves me away from the nice generic method that the existing version gives me. I guess I could use it to complement it but then its starting to lose some of the charm. I also am implementing IModelEnrichers which can do custom per view model logic.
Any thoughts on a nice way to implement this?
I implemented the solution using pairs of Attributes to define a requirement for data on a ViewModel and a provider of data a repository or a service within my domain. See my follow up question asking whether this is a good idea.

What table fields would I need here?

I want to create a commenting model with a twist. I want there to be multiple commenting columns like on hunch.com, except that a user can decide how many columns there should be. Also, a user can decide the title for each column.
This is rather dynamic, so how would I set up my tables for this?
Seems like a perfect use case for NoSQL. I'd use something like CouchDB or Mongo here. Since there you don't have a schema you can add the attributes as needed.
Since you cannot really change the attributes of a model, if you want to create dynamic model attributes, you can have 3 models :
User
Attribute
UserAttribute
Now, you can add as many attributes are you want (Attribute is the static representation of an attribute). Then, a user can have many attributes through user_attributes.

Django ModelAdmin queryset override doesn't work

I'm trying to override the queryset() of a ModelAdmin class so that the list of objects shown in admin would be sorted by two levels.
I've tried the following code, but it does not work, i.e. the table is not sorted as expected
class ProductAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(ProductAdmin, self).queryset(request)
return qs.order_by('category','market')
list_display = ('category', 'market', 'name', 'quantity')
admin.site.register(Product, ProductAdmin)
btw, you can't use ordering = ('category','market') as django specifically states that only the first item in the ordering tuple takes effect (see note in the documentation here)
get_queryset works in Django 1.8.
I had this exactly problem. Here's what I did:
I subclassed ChangeList and overrode ChangeList.get_query_set to redo the correct order_by that was previously changed by ChangeList.get_ordering:
This is what I did in my case (I'm using django-easytree, but the same applies for django-mptt):
class MyChangeList(ChangeList):
def get_query_set(self):
qs = super(MyChangeList, self).get_query_set()
return qs.order_by('tree_id', 'lft')
Also, check these tickets:
"NFA: Don't override order_by if no default ordering is specified"
"Admin ChangeList doesn't apply 'order_by' clause specified by ModelAdmin.queryset"
The release notes for Django 1.4 say that Django now supports Multiple sort in admin interface:
The admin change list now supports sorting on multiple columns. It
respects all elements of the ordering attribute, and sorting on
multiple columns by clicking on headers is designed to mimic the
behavior of desktop GUIs.
And from ModelAdmin ordering:
Set ordering to specify how lists of objects should be ordered in the
Django admin views. This should be a list or tuple in the same format
as a model's ordering parameter. [...] Django honors all elements in the list/tuple; before 1.4, only the first was respected.
On a semi-related note - if you do override queryset to provide a custom sort order, it seems that the Changelist will override that sort order. It applies any sorting found in the ordering parameter, and if there isn't one, it applies a default sort by pk, thus negating any sorting you did in queryset.
I think it's supposed to work - at least this Django Ticket says fixed. But I was just trying to apply a custom sort using queryset a few days ago, and it didn't work at all for me. Even sorting on a single field, seemed to be overridden in the final view. So either I did something wrong, or it's not all that fixed. :)
Note that it is possible to do a custom sort via code, but you have to subclass Changelist, and override its get_query_set() method, as per this snippet. (Although this is overkill, if you only need multiple fields sorted, since Django 1.4 now supports multiple fields).

How can I modify the queryset in the change list view depending on a parameter I set in the URL

My problem is the following and it is related to the change list view of the admin interface.
I have a workorder model with several fields to caracterize the work order.
They are : type, nature, scheduling_type (and others).
When I see the list view, I would like to be able to change the filter (thus be able to create complex ones depending on the values of the different fields of the workorder model - the ones above and dates for example).
I have found post showing how to modify the default queryset (using managers for example) but I can't find a post that will use a value that is given in the url (ex. admin/workorder/planned_corrective). When the parameter planned_corrective is found, it must be used to select the appropriate queryset or manager and render the corresponding list.
As a add on, I want from that list to be able to use the standard admin options (like list filters, search ...) on that query.
Hope it is clear and thanks in advance for your help.
It sounds like you're after a RESTful interface.
You could accomplish much of this just by being clever with your urls.py - ie, defining admin/workoder/planned_corrective and every other possible parameter that could be encoded in the URL.
A lot of this can also be accomplished just by adding a get-absolute-url method to your models.
Or, you could the effort into using something like the django-rest-interface in your app.

Symfony Admin Generator in multi user setup (restricting records in LIST view)

I am using SF 1.2.9 to build a website. I want to use the admin generator to provide admin functionality for the object models I have used (specifically LIST, edit and delete).
I have read the Symfony docs (Chapter 14), but unless, I am very much mistaken, all examples I have come accross so far, seems to be written for a single user environment only. Meaning that the list of records returned to the user is essentially, ALL the records in that table. In a multiuser environment, this is irresposible at best, and potentially, a security threat. It is a necessary requirement to restrict the list of records returned to a user to only those that they own (i.e. created).
Suppose I have a table with (YML) schema like this:
foobar_dongle:
id: ~
title: varchar(255)
info: longvarchar
owner_id: ~
created_at: ~
where owner id is a FK into a user table.
Assume I generate an admin module like this:
symfony propel:generate-admin backend FoobarDongle --module=dongle
Question:
How do I modify the list of records returned to a user in the LIST part of the code generated by the admin generator? As I mentioned above, currently, (i.e. out of the box), the admin generator presents the user (rather naively, I feel), with the ENTIRE set of records for the model being administered. I need to be able to restrict that list somehow, so that I can only return records owned by that user.
This is what I am trying to find out how to do.
I would be most grateful to anyone who can show me how I can restrict the list of records returned when using the admin generator for administration of an object model. Ideally, I would like to be able to specify a custom method that has all the custom 'filtering' logic - but so long as I can restrict the LIST of records a user can see (in admin), to only the records that he is the owner of, that is all I want to be able to do.
If you only want to restrict the returned objects in one or two modules, do this:
Go to the actions.class.php file of your module. There should be no methods by default and the class should inherit from autoModuleNameActions you. Insert the following method:
protected function buildQuery()
{
$query = parent::buildQuery();
// do what ever you like with the query like
$query->andWhere('user_id = ?', $this->getUser()->getId());
return $query;
}
But this becomes unhandy if you do it for more modules. In this case I would advice to create a new admin generator theme.
And if you want to make the query depending on some custom parameter in the admin generator config file, then you have to extend this file. But is not just done with adding a new parameter. You can read this article how to do this.
If you want to know more about the auto generated classes, have a look at this class: cache/[app]/[env]/modules/auto[ModuleName]/actions/actions.class.php.
Edit after comments:
I think you looked at the wrong class. Look here: cache/[app]/[env]/modules/auto[ModuleName]/actions/actions.class.php.
I set up a Propel project to check it and the method that is interesting for you is:
protected function buildCriteria()
{
if (is_null($this->filters))
{
$this->filters = $this->configuration->getFilterForm($this->getFilters());
}
$criteria = $this->filters->buildCriteria($this->getFilters());
$this->addSortCriteria($criteria);
$event = $this->dispatcher->filter(new sfEvent($this, 'admin.build_criteria'), $criteria);
$criteria = $event->getReturnValue();
return $criteria;
}
I also posted the whole content of this class to pastebin. It is a lot, the function is in line 245. Even if you don't find this class, you should be able to override this method like this:
protected function buildCriteria()
{
$criteria = parent::buildCriteria();
// do something with it
return $criteria;
}
I don't know about these criteria objects, so I can't help you with that but I hope the other things help you.
You should use sfGuardPlugin to provide your login/user functionality - it includes user groups and permissions that can be assigned to users and/or groups.
Using security.yml you can then configure which permissions/credentials are required to access individual actions. IE: you can allow everyone to access the list/update/delete actions, but only people with the create permission to access the create page.
The docs for sfGuardPlugin are worth reading:
http://www.symfony-project.org/plugins/sfGuardPlugin
Plus this section from the jobeet tutorial covers sfGuard and also use of security.yml and credentials:
http://www.symfony-project.org/jobeet/1_2/Propel/en/13
And to round off, this page from the book is relevant too:
http://www.symfony-project.org/reference/1_2/en/08-Security (although not sure it covers anything that isn't in the page i linked from jobeet)

Resources