I have trivial complex page.
For example: content(left) and sidebar(right).
Sidebar consists of a plurality of parts. We take a look at one of theese. This fragment contains list of users(for example) subscribed to the event. The list displays only 5 users and "More" button, which loads more users when clicked (ajax).
If i use:
{% render controller('SomeBundle:Event:subcribers', {page: 1, limit: 5}) %}
Or:
{% render path('event_subcribers_route', {...}) %}
It will cause a subrequest. Notice: in this case i use this route 'event_subcribers_route' for ajax request.
Question: Maybe exists way to avoid dozens subrequests?
I'm aware that i can use services, with render logic inside them, but maybe exists some best practice for this common task.
What is wrong with subrequests?
Maybe you think about more traffic between browser and server as it will happen if you have many images, css files or javascript directives in your HTML.
This is not the point using internal subrequests within the Symfony framework. actually this is just some program-logic or design pattern.
browser->request->[router->controller->view]->response->browser
^ |
| |
|<-subrequest-V
This is a very simplified schema of a subrequest like it happens using the {% render controller() %} in Twig. Between the [ and ] is inside Symfony. You just stay into the application.
Everytime you include that piece of HTML you will need to do the according subrequest to the database no matter which method you use.
But, you can optimize the query to recover those users. You can select only the fields you actually need (username, slug, etc.) and also you can do it on a single query. That single query will become a prepared statement and you can even put index on the table to make the query faster.
In addition, you can implement the symfony cache system to avoid those subrequest that symfony does on every load. If your snippet loads always the same 5 users or they change after X minutes you can easily implement an efficient cache.
Related
problem : i have to allow users to have different colors for buttons , icons , text color as per their preference using spectrum.js
i have tried to solve this using dotless for that i created a file .less and added all values. now issue is that i have to get values from databased based on loggedInuser and have to dynamically change
#back-color: blue;
#font-color: red;
to different values and this has to be done run time not compile time. i know it will cost me some delay but i dont know how to solve it other wise.
i have been thinking of different solution rather to have a less file why not on saving time i create a css file save in database and when user gets logged in create a css file and inject in to header
<link href="~/Content/dynamic.css" rel="stylesheet" />
can some one help me or any suggestion regarding this??
any help will be appreciated
Option 1
Implement special handler for resource, that represent css customized by user.
This handler must:
Make lookup (by userId) to cache where already rendered less (i.e. css) is stored;
If cache has entry for requested user, then write css to response and finish handling of this request;
If cache has no entry for requested user, then render less for this user, store it in cache and go to step 2.
You also should remove/update cache entry when user changes his color theme.
You can implement cache as you wish: in memory, inside database or inside static files that named (for example) like %userId%.css.
Option 2
Instead of render less on server side (and consume server resources) you can render less on client dynamically.
Exmaple: http://jsbin.com/wiqosutexe/5/edit?html,js,output
Include lessjs http://lesscss.org/#download-options;
Provide less template to client script (get with ajax, include in script itself or somehow else);
Use user preferences to make substitutions to less template.
Render template and insert results (plain css) into dynamically created style tag.
Lets say I have two controllers that work with the same entity, and use the same set of templates. Every template is supposed to generate buttons/forms/links with URLs to actions of controller that generated this template. So basically, the only thing that is different in the templates are the URLs generated.
You can imagine the problem like a admin CRUD controller with a newAction and editAction, which use the same template, but form actions must differ. My case is more complicated than that, though.
I considered following:
Setting the routes from the controller, but it feels like a lot of code that is out of place.
Different set of templates. Seems like anti-DRY and a lot of reused code.
Using template inheritance, where base template is the one with all the HTML, and child templates only contain the links, but it feels really hacky.
Is there a clever approach to solve this problem?
EDIT: My problem is not generating CRUD. This is more of a "best-practice" question.
I encountered this problem while implementing something like a eshop cart with tons of javascript logic bound to it. It appears twice: in the website, and in a iframe, used by some other devices (iPads and stuff). Both carts have to look the same, but because of different logic, the links must lead to different URLs.
What I ended up doing for now is having 2 templates
The one with all the markup, cart.html.twig:
{% set edit_cart_item = path('edit_cart_item') %}
{% set remove_cart_item = path('remove_cart_item') %}
...html...
Edit item
...more html...
The one for usage in iframe, public_cart.html.twig:
{% extends 'MyCartBundle::cart.html.twig' %}
{% set edit_cart_item = path('public_edit_cart_item') %}
{% set remove_cart_item = path('public_remove_cart_item') %}
Does the problem have some better solution in all the fancy OOP principles?
There isn't a 'clever' approach really. Why not just use the specified Doctrine command to generate it for you, and then go from there? http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_doctrine_crud.html
php app/console generate:doctrine:crud with various options
That will get you a solid base done in an 'appropriate' manner, and then you can perform your customizations.
EDIT:
After reading your updated post, I would have a look at this: http://symfony.com/doc/current/book/forms.html#changing-the-action-and-method-of-a-form
So, if you'd like, you can handle the logic of which form to display by passing in options to the form, and then setting the target via setAction():
$form = $this->createFormBuilder($task)
->setAction($this->generateUrl('target_route'))
;
By design, Symfony gives you a lot of flexibility in how to do things. A good reference of their best practices for forms can be found here: http://symfony.com/doc/current/best_practices/forms.html
I also think what you're doing is just fine. When I have complex cases for forms I like to create a Twig template just for the form itself, and then include that in my other templates. In that template you can pass the target route to it if you'd like, and then you'd just have one form template.
Inside my _layout view I have added the following link , to refresh the current page as part my breadcrumb bar:
#(aoutput == "Index" ? "Home" : aoutput)
The above is working well on my development environment , but I am not sure If using the Request.Url.AbsoulteUri is the correct way to reference the current page URL ?
AbsoluteUri includes the scheme (such as http), the host, the port, the path, query string data and the fragment. As far as I know the fragment will not be included in the current URL because it is not sent with the request (that is, it's handled by the browser client-side).
This should be fine to use and is unlikely to cause you issues. Just be aware that query string data is included, which means that if you had a (poorly-designed) data manipulation system such as /Users/Index?action=deleteMostRecentUser then the user might accidently delete users because the URI would include the action.
Alternatives are
Absolute Path: /Home/Index
Path & Query: /Home/Index?query=keyword
You can use it as you mentioned.
Better way you make a separate partial view to implement breadcrumb.
And pass wanted model from Controller side. (Or in ViewBag)
The main benefit is you'll get is better control over Logic also flexible for future changes.
Hope helps.
So I'm writing a Django based website that allows users select a color scheme through an administration interface.
I already have middleware/context processors that links the current request (based on domain) to the account.
My question is how to dynamically serve the CSS with the account's custom color scheme.
I see two options:
Add a CSS block to the base template that overrides the styles w/variables passed in through a context processors.
Use a custom URL (e.g. "/static/dynamic/css/< website_id >/styles.css") that gets routed to a view that grabs all the necessary values and creates the css file.
I'm content with either option, but was wondering if anyone else out there has dealt with similar problems and could give some insight as to "Best Practices".
Update : I'm leaning towards option number 2, as I think this will allow for better caching down the road. So it's dynamic the first time, gets stored in memcache (or whatever), and invalidated when a user updates their settings in the admin site.
Update: Firstly, I'd like to thank everyone for their suggestions thus far. All the answers thus far have focused around generating static files. Though this would work great in production, it feels like a tremendous burden during development. If I wanted to add a new element to be styled, or tweak existing styles I'd have to go through and recreate each and every css file. Sure, this could be done with a management command, but I just don't feel it's worth it. Doing it dynamically would add 1 maybe 2 queries to each page load, which is something I'm not worried about at this stage. All I need to know is that at some point I will be able to cache it without rewriting the whole thing.
I've used option #2 with success. There are 2 decent ways of updating the generated static files that I know of:
Use a version querystring like /special_path.css?v=11452354234 where the v parameter is generated from a database field, key in memcached, or some other persistent file. Version gets updated by admin, or for development you would just make the generation not save if the parameter was something special like v=-1. You'll need a process to clean up the old generations after some time.
Don't use a version querystring, but have it look first for the generated file, if it can't find it, it generates it. You can create a cron job or WSGI app that looks for filesystem changes for development, and have a hook from your admin panel that deletes generations after an update. Here's an example of the monitoring, which you would have to convert to be specific to your generations and not to Django. http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode#Monitoring%5FFor%5FCode%5FChanges
Could generate the css and store it in a textfield in the same model as the user profile/settings. Could then have a view to recreate them if you change a style. Then do your option 1 above.
Nice question.
I would suggest to pre-generate css file after colors scheme is saved. This would have positive impact on caching and overall page loading time. You can store your css files in directory /media/css/custom/<id or stometing>/styles.css or /media/css/custom/<id or sth>.css and in template add <link rel="stylesheet" href="/media/css/custom/{{some_var_pointing _to_file_name}}" />
You can also do the trick with some random number or date in css file name that could be changed each time file is saved. Thanks to this browser will load the file immediately in case of changes.
UPDATE: example of using model to improve this example
To make managing of those file easy you can create simple model (one per user):
class UserCSS(models.Model):
bg_color = models.CharField(..)
...
...
Fields (like bg_color) can represent parts of your css file. You can ovveride save method to add logic that creates css file for user (by rendering some template).
In case your file format change you can make changes in your's model definition (with some default values for new fields), make little changes in template and run save method for each exisintg instance of class. This would renew your css files.
That should work nicely.
I would create an md5 key with the theme elements, store this key in the user profile and create a ccs file named after this md5 key : you gain static file access and automatic theme change detection.
I know that I need to add the tracking code snippet at the bottom of all my pages, but is there a central location to do this?
Or do I need to add this tracking code to all of my templates?
I guess that I could wrap the snippet in a user control, or external .js file, and reference it on each page, but is there a global footer somewhere? The site I'm working on has about 30-40 layouts, and adding it to each one would be a pain!
Thanks in advance!
Actually, the role of a Sitecore layout is exactly this; to act as a global file that all individual page templates "derive" from.
Normally you'd stick the analytics code into the master layout, and use Sitecore sublayout/placeholder techniques to construct the various page templates you need. You would not normally need more than perhaps one or two layouts for any device you are serving content to. And I guess for most sites, the only device in use is regular web content delivery.
That being said, what you could do, is have all the layouts inherit their codebase from a common base class (inheriting from Page), and inject the google code centrally from here. Would still require you to go through all layout files however.
I have not tried the module, I think that is codebehind version. I have made this in XSLT, its pretty fast and easy to make. I have footer.xslt where I put the code that simply checks if page you are standing on uses template that I want to index and does not belong to page names that I want to exclude. Then I have an item with a custom template for Google Analytics with following memo fields.
IncludeTemplates -field contains list of templates that I want to include for analytics :
ExcludeItemsNames -field for excluding pages by item name
contains($includeTemplates, concat('|',./#template,'|')) and not(contains($excludeItemNames, concat('|',./#template,'|')))
Remember #key and #template is always in small letters
If you run many domains don't forget to add pageTracker._setDomainName("www.example.com"); in analytics script so you can separate sub-domains etc. if they use same footer.xslt
Normally we consider the actual Google code as content. Within Sitecore we normally have a settings folder, something like /sitecore/content/settings. This exists outside the root of the site. Beneath this have a settings item with a plain multi-line text field, I think the field type is memo or something similar.
Afterwards create an XSLT that renders out the content of this settings item. Something like (assuming the field is called value in the setting item):
<xsl:value-of select="sc:fld('Value','/sitecore/content/settings/footerJavaScript')" />
You may or may not need to set the disable-output-escaping attribute.
Then on the aspx page that your pages use as the template add a control that looks at the xslt rendering:
<sc:XslFile runat="server" Path="/xsl/footerJavaScript" />
The reason that we normally keep the javascript as content is this allows the client to change the analytics code without having to contact us.