Symfony 2: Displaying tables? - symfony-2.1

I'd like to display some rows of data from a database table. I'm keen to get some advice on how to best achieve this.
Let me explain how I do it now and why this question has been raised: I currently have a scheme whereby the controller loads data into an array, and then passes this to the twig template. The twig template then calls a "utility" controller to display the array. The utility controller takes care of formatting the fields, etc. So, for example:
Controller:
$cols = array('1','2','3');
$rows = array();
for (...) {
$rows[] = ...
}
return array(
'cols' => $cols,
'rows' => $rows,
);
Twig:
{% render 'Bundle:Table:print' with { 'cols': cols, 'rows': rows } %}
However, when I tried to move to Symfony 2.2, I ran into a few problems because of the way that internal calls are now handled in 2.2. See http://symfony.com/blog/new-in-symfony-2-2-the-new-fragment-sub-framework
It looks like the arrays are converted to URL parameters, and then parsed out again (using parse_str). This lead to two distinct problems:
For larger tables, PHP was limited to 1000 items in the arrays. (Yes, I can increase the limit, but is that sensible?)
DateTime types seemed to lose their typing and were seen as just arrays.
So, is my original approach workable going forward? If not, what approach should be used?
Thanks.

A third party suggested "What about writing a Twig extension instead of using a Symfony controller?"
http://symfony.com/doc/current/cookbook/templating/twig_extension.html

Related

How to avoid long list of data in Django view's render function?

I am new to Django and am trying to build my first Django website. The content of my website requires a lot of data retrieved from my database(i.e. bar charts of latest data) and currently my solution to this is using the render(request, 'index.html', data) function to pass data to index.html template and use something like var salesValue = {{salesValue|safe}} to use the values.
The data dictionary looks like this in my view function. I have omitted the code for data extraction/formatting of the queryresults for simplicity:
queryresult0 = model0.objects.filter(...)
queryresult1 = model1.objects.filter(...)
queryresult2 = model2.objects.filter(...)
...
data = {
'salesValue0' : queryresult,
'salesValue1' : queryresult1,
'salesValue2' : queryresult2,
...(and so on and so on)
}
These values are separate variables because the database queries involve multiple tables in multiple databases.
This solution works (though I'm not sure it's a good practice) but it didn't take long before the data dictionary gets so long that it's hard to keep track of everything, plus the code gets very clumsy as well.
Is there a more efficient/elegant way to send lots of data to template? Maybe Switch to model base view instead of function based view? Use AJAX calls? Or maybe I should not be doing this in Django? Any suggestions are welcome! Thanks in advance and I apologize if this question seems like an open-ended question, but really it is a very specific problem that's troubling me:)

Tabulator - exclusive header filters - how?

I wrote and support a little web app for our local animal shelter to help volunteers locate dogs. I chose Tabulator because it had great features and was easy to use and have been very happy with my choice. For the first version of the app I used external input fields to search and manually did all the wiring to support live search.
Now I am working on v2 and am trying to use header filters. My problem is that the filters need to be exclusive, that is, using filter1 clears/disables filters 2 and 3, using filter2 clears/disables 1 and 3, and so on. With the external search fields I used focus() events to do this. When I try using jQuery on(focus) delegates to do the same with header filters and for example table.setHeaderFilterValue("field1", "") it does not work; the event triggers but the input box never gets the focus so I cannot type in it. I've tried different events like click; but nothing I've tried works properly.
I've studied the docs and struggled with this for several hours. I've considered hooking dataFiltering() and eliminating the filters I don't want, but I'm not sure how to identify the filter that I want to keep, and there is still the matter of the text in the fields to be dealt with. I'm sure it doesn't help that front-end work is not my area of expertise, though so far I've managed well enough. Is there a simple or normal way to do this that I'm just not seeing?
For the record, I found a way to do exclusive filtering with header filters with a single event callback:
\$(document).on("focus", ".tabulator-col input[type=search]", function() {
var hfNames = ["name", "anum", "kennel"];
var fieldName = \$(this).closest(".tabulator-col")[0].getAttribute("tabulator-field");
hfNames.map(function(hfN) { if (hfN != fieldName) table.setHeaderFilterValue(hfN, "") });
});
The three hfNames are the field names of the columns with filtering on. Yes, I could have derived them dynamically, but it didn't seem worth it for a small app like this.
As I suspected, the key was simply a better knowledge of JQuery.

How to attach Content Parts only to specific Types or specific Content Items?

I have two similar problems that I suspect have a common solution.
1) I'd like to create custom Parts that are Attachable, but only to specific content types, only Taxonomies for example. It would be really cool if that was possible out of the box through migrations e.g something like .Attachable(cfg => cfg.ToType("Taxonomy")) but I don't think it is.
Currently, to prevent my custom Part from being used on content that it's not intended for, I just write checks in the driver methods:
protected override DriverResult Editor(CustomPart part, dynamic shapeHelper)
{
if (part.ContentItem.ContentType != "Taxonomy") return null;
return ContentShape("Parts_Custom_Edit", ...
}
Is this a good way to go about it? Would the Handler be better fit for this kind of logic?
2) Similarly, I'd like to be able to conditionally attach different Parts to different individual Content Items. For example, I would like only first level parent Terms in a Taxonomy to have some fields while child Terms have some others.
The best way I can currently come up with to handle this is to just create one Part that holds all fields and run similar checks to the one above in its Driver methods to return different models depending on its container. Then in the template View I check which fields to render:
#if (Model.ThisField != null) {
<div>#Html.EditorFor(m => m.ThisField)</div>
}
else {
<div>#Html.EditorFor(m => m.ThatField)</div>
}
Ideally I'd like to create one attachable Part that's capable of adding several non-attachable secondary Parts to existing Content Items when it is attached to a Type and to new Content Items when they are created or updated. Is there a painless way to do this? I think 'Welding' might be what I need but I haven't been able to find any documentation or tutorials that can explain Welding to me like I'm five.
I think you need to implement a dynamic welding approach. I had to solve a similar issue, it is posted here. Hope this helps.

Does BuildShapes makes a database call?

I am trying to generate custom markup for a bunch of queries. One query is filtered on the "Spotlight" content type, and has a shape layout that's pointing at Spotlight.cshtml.
Spotlight.cshtml
#{
dynamic shapes = Model.BuildShapes;
}
#foreach (dynamic shape in shapes())
{
#Display(shape)
}
I'm using BuildShapes instead of BuildDisplay, because the latter makes a call to the database. Does BuildShapes also call the DB?
As far as I can tell from looking at ShapeLayout.cs, BuildShapes is calling BuildDisplay, which is calling drivers to ask them for shapes. So if the drivers are making database calls, so is BuildShapes.
The more important question is what exactly are you trying to do? A lot of context is missing.

Is list function a good candidate for my scenario?

I have a view in couchDb that is defined like this
function (doc) {
if (doc.url) {
var a = new Date(doc.postedOn);
emit([a.toLocaleDateString(), doc.count, doc.userId], {
_id: doc.userId,
postTitle: doc.postTitle,
postSummary: doc.postSummary,
url: doc.url,
count: doc.count
});
}
};
This gives me the result in a format that I want.Sorted first by date then by count and then by userID.
However I have trouble querying it.What I want is to query this view just by userId.That is leave the date and the count parameter null.
_view/viewName?limit=20&descending=true&endkey=["","","userId"]
does not give me the desired result.
Should I be using list function to filter out the results of the view.Is there any impact on performance if I do this?
This quote from the definitive guide first gave me the idea that list functions could be used to filter and aggregate results.
The powerful iterator API allows for flexibility to filter and aggregate rows on the fly, as well as output raw transformations for an easy way to make Atom feeds, HTML lists, CSV files, config files, or even just modified JSON.
List function has nothing to do with your case. From the docs you've linked to yourself:
While Show functions are used to customize document presentation, List functions are used for same purpose, but against View functions results.
Show functions are used to represent documents in various formats, commonly as HTML page with nicer formatting. They can also be used to run server-side functions without requiring a pre-existing document.
To solve your problem just change the order of the emitted keys, putting userId first, i.e.:
[ doc.userId, a.toLocaleDateString(), doc.count ]
and update your query appropriately.
If changing the order of emitted keys is not an option, just create another view.

Resources