October CMS and navigation on current page - laravel

I am trying to get the basically the active class applied to the current page. As it goes, the builder plugin is setting the URL through:
<a href="{{ detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }) }}">
However I am new to October so I am not sure how to reference this.page.id in comparison to the url set above.
Basically I want this:
{ set UrlParam = detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }
{% if this.page.id == UrlParam %} class="active" {% endif %}
Any ideas?

One of the best debugging plugins out there for OctoberCMS is this: https://octobercms.com/plugin/davask-dump
That plugin makes connecting your twig templates to your database / php rendering a breeze.
After installing that plugin you can use {{ d(variable) }} instead of {{ dd(variable) }} and get more information on the array nests etc.
So I would do {{ d(UrlParam) }} and {{ d(this.page.id) }} in your twig template. See what the dump has to say about each of those variables. For clarity I do believe you need the % here {**%** set 'variable' **%**}.
I am also not a fan of the builder component and I use the PHP section on the page / partial pages. And establishing a class with the use function and access the data with $this['variable']. Maybe worth looking into here is a quick example:
Pluginauthor\Plugin\Models\Plugin;
function onStart() {
$plugin = Pluggin::all();
$this['plugin'] = $plugin;
}

Related

After browser back button load last search

I have own plugin in October CMS what have a onFilter() function whats return and displays partials with data. When user click on name it redirect him to a detail page. And when user click back button in browser I want to display his last search.
I tried something like Session::push('data', $data) in onFilter() method and Session::get('data') in onInit() but it didnt work. $data is a list of pubs.
Had anyone same problem?
Edit
public function onFilter()
{
$result =
Lounge::filterLounge($categories, $tags, $regions, $paidIds, $price_from, $search);
Session::put('nameFilter', $result);
return [
'#list' => $this->renderPartial('loungelist::list.htm', [
'list_data' => $result])
];
}
public function getNameFilter() {
$nameFilter = Session::get('nameFilter');
return $nameFilter;
}
In partial .htm
{% set list_data = __SELF__.getNameFilter() %}
{% for lounge in list_data %}
{{ lounge.name }}
{% endfor %}
As #mwilson mentions I would use window.history on the front end with the pushstate() function so that when each filter is changed you push state including query strings before firing to php to get the filtered content. I have done this before and works very well.
You should post more code for us to be more helpful. I am assuming you are using a component. Are you using ajax? Session will do the job.
In your component.php put onNameFilter() event you can push the data into the session with Session::put('nameFilter' $data);. I suggest using more specific labels for your events and keys so I chose 'nameFilter'.
You will want to use a method in your component.php to call the session.
public function getNameFilter() {
$nameFilter = Session::get('nameFilter');
return $nameFilter;
}
Now in your partial.htm you can set the name filter data and access it as long as it is in the session:
{% set nameFilterData = __SELF__.getNameFilter() %}
EDIT TO SHOW REFLECTED CODE
I don't understand how it works the first time. What does your CMS Page look like? How do you show the filter the "first time"?
Your CMS Page has {% component 'something' %} right? Then in your default.htm file you have {% partial __SELF__~'::list %}?
In your partial you will need to display the list_data. Does this show anything?
{% for list in list_data %}
{{ list_data.name }}
{% endfor %}

OctoberCMS Builder Plugin to Show Data on Front End

This my first time to use OctoberCMS, and they provide the Builder Plugin in order to help the developer builds plugin in minutes.
I try to use this plugin to show the data on the front end especially when using Components > Builder > Record list, but the documentation didn't give enough example to get data from some fields. The example on the internet is just show how to get the data from one field.
My code is shown below:
[builderList]
modelClass = "Budiprasetyo\Employees\Models\Employee"
scope = "-"
displayColumn = "name"
noRecordsMessage = "No records found"
detailsPage = "-"
detailsUrlParameter = "id"
pageNumber = "{{ :page }}"
in my case, I want to get the data not only "name" field, but I also want to add "email", "facebook" fields.
I have tried to make it into:
displayColumn = "name", "email", "facebook"
but it returns no data shown and I have tried to make it into array:
displayColumn = ["name", "email", "facebook"]
and it's the same result, no data is shown.
I appreciate any helps, thank you.
Actually I don't like to use plugins' components. Sometimes it doesn't retrieve any data. I don't know why maybe it's just because of wrong using.
Anyway, The best way to retrieve the data from your plugin is to navigate to the code section and then write onStart() function and start to retrieve to data.
function onStart()
{
$data = \Authorname\Pluginname\Models\Model::find(1);
$this['data'] = $data;
}
And this way you'll have a data variable in the markup section.
On the frontend cms page, you need to replace the component call with your custom partial. Your partial file should look something like this:
*podcastList is the component name
{% set records =podcastList.records %}
{% set displayColumn =podcastList.displayColumn %}
{% set noRecordsMessage =podcastList.noRecordsMessage %}
{% set detailsPage =podcastList.detailsPage %}
{% set detailsKeyColumn =podcastList.detailsKeyColumn %}
{% set detailsUrlParameter =podcastList.detailsUrlParameter %}
{% for record in records %}
<span class="date">{{ attribute(record, 'date') }}</span>
<span class="title">{{ attribute(record, 'title') }}</span>
<p>{{ attribute(record, 'description') }}</p>
{% endfor %}
Obviously, this is simplified version, but you get the point. You can easily define more columns without touching the page component settings.

Optimising html/template Composition

I'm looking to see if there is a better (faster, more organised) way to split up my templates in Go. I strongly prefer to stick to html/template (or a wrapper thereof) since I trust its security model.
Right now I use template.ParseGlob to parse all of my template files in within init().
I apply template.Funcs to the resulting templates
I set a $title in each template (i.e. listing_payment.tmpl) and pass this to the content template.
I understand that html/template caches templates in memory once parsed
My handlers only call t.ExecuteTemplate(w, "name.tmpl", map[string]interface{}) and don't do any silly parsing on each request.
I compose templates from multiple pieces (and this is the bit I find clunky) as below:
{{ $title := "Page Title" }}
{{ template "head" $title }}
{{ template "checkout" }}
{{ template "top" }}
{{ template "sidebar_details" . }}
{{ template "sidebar_payments" }}
{{ template "sidebar_bottom" }}
<div class="bordered-content">
...
{{ template "listing_content" . }}
...
</div>
{{ template "footer"}}
{{ template "bottom" }}
My three questions are:
Is this performant, or do the multiple {{ template "name" }} tags result in a potential per-request performance hit? I see a lot of write - broken pipe errors when stress testing heavier pages. This might just be due to socket timeouts (i.e. socket closing before the writer can finish) rather than some kind of per-request composition, though (correct me if otherwise!)
Is there a better way to do this within the constraints of the html/template package? The first example in Django's template docs approaches what I'd like. Extend a base layout and replace the title, sidebar and content blocks as needed.
Somewhat tangential: when template.ExecuteTemplate returns an error during a request, is there an idiomatic way to handle it? If I pass the writer to an error handler I end up with soup on the page (because it just continues writing), but a re-direct doesn't seem like idiomatic HTTP.
With some help on Reddit I managed to work out a fairly sensible (and performant) approach to this that allows:
Building layouts with content blocks
Creating templates that effectively "extend" these layouts
Filling in blocks (scripts, sidebars, etc.) with other templates
base.tmpl
<html>
<head>
{{ template "title" .}}
</head>
<body>
{{ template "scripts" . }}
{{ template "sidebar" . }}
{{ template "content" . }}
<footer>
...
</footer>
</body>
index.tmpl
{{ define "title"}}<title>Index Page</title>{{ end }}
// We must define every block in the base layout.
{{ define "scripts" }} {{ end }}
{{ define "sidebar" }}
// We have a two part sidebar that changes depending on the page
{{ template "sidebar_index" }}
{{ template "sidebar_base" }}
{{ end }}
{{ define "content" }}
{{ template "listings_table" . }}
{{ end }}
... and our Go code, which leverages the map[string]*template.Template approach outlined in this SO answer:
var templates map[string]*template.Template
var ErrTemplateDoesNotExist = errors.New("The template does not exist.")
// Load templates on program initialisation
func init() {
if templates == nil {
templates = make(map[string]*template.Template)
}
templates["index.html"] = template.Must(template.ParseFiles("index.tmpl", "sidebar_index.tmpl", "sidebar_base.tmpl", "listings_table.tmpl", "base.tmpl"))
...
}
// renderTemplate is a wrapper around template.ExecuteTemplate.
func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
// Ensure the template exists in the map.
tmpl, ok := templates[name]
if !ok {
return ErrTemplateDoesNotExist
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
tmpl.ExecuteTemplate(w, "base", data)
return nil
}
From initial benchmarks (using wrk) it seems to be a fair bit more performant when it comes to heavy load, likely due to the fact that we're not passing around a whole ParseGlob worth of templates every request. It also makes authoring the templates themselves a lot simpler.

Building a widget manager on top of Symfony 2 (multiple controllers in one page)

Use case
I am developing a CMF on top of Symfony2. One of the features will be the support of "widgets": an possibility for end users to add small 'blocks' or 'modules' to a page. Examples:
A small login form
A list of products
Some photo's from a gallery
A shopping cart
The idea is that most of those widgets will link to to normal, full page Routes/Controllers.
For example: a user want a list of popular products in a sidebar on a content page. The items will link to the normal /product/{name} route of the ProductController. But the list in this case would be a widget. The end user can define where it must be placed, and for example, how much items must be shown.
The behavior of the 'widgets' is the same as regular Symfony2 controllers, it has routes, actions, it renders a view, etcetera. There is a WidgetManager with a catch-all route to load the widgets, configure them and render them in the right place.
I have not that much experience with Symfony2, but I am playing wit it now for more then 3 months. I definitely want to stay with Symfony2, but will need to add some magic to realize some of my ideas.
Question
What is the best way to support rendering multiple controllers (widgets) in one request?
Research
Symfony's TwigExtension "ActionExtension" contains a "render" method, which contains the basic idea:
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
(Documentation: http://symfony.com/doc/current/book/templating.html#embedding-controllers)
But it is quite limited. Some problems with this approach:
I cannot configure the 'widgets' before rendering them (for example: $myWidget->set('show_toolbar', false)), I don't want to pass all options as controller action parameters.
It is not possible to use template inheritance. I need this for example for 'injecting' the asset references (javascript/css) in de base <HEAD> block.
What I want
I want the following code to work (this is a simplified example):
// Serius\PageBundle\Controller\PageController.php
// executed by a catch-all route
public function indexAction($url) {
// load CMS page, etc
$widgets = $this->loadWidgets($page); // widgets configuration is stored in database
// at this point, $widgets is an array of Controller *instances*
// meaning, they are already constructed and configured
return $this->render("SeriusPageBundle:Page:content.html.twig", array(
'widgets' => $widgets
));
}
Serius\PageBundle\Resources\views\Page\content.html.twig
{% extends 'SeriusPageBundle::layout.html.twig' %}
{% block content %}
{% for widget in widgets %}
<div>
{% render widget %}
<!-- Of course, this doesn't work, I would have to create my own Twig extension -->
</div>
{% endfor %}
{% endblock %}
An example of a widget template:
{% extends '::base.html.twig' %}
{% block stylesheets %}
My stylesheets
{% endblock %}
{% block body %}
This is a shoppingcart widget!
{% endblock %}
How can I achieve this? Do someone have experience with anything like this? I already looked at the Symfony CMF project, but it has no support for this (as far as I could find out).
I have something similar going around and I think that this code will help you. In chosen template you get the variables with the names of blocks.
public function render()
{
$modules = $this->moduleService->getModules();
foreach($modules as $m){
$templateName = $m->getTemplateName();
$template = $this->twig->loadTemplate($templateName);
$blockNames = $template->getBlockNames();
foreach($blockNames as $b){
if(isset($this->blocks[$b]) == false)
$this->blocks[$b] = '';
$this->blocks[$b] .= $template->renderBlock($b, array('a' => 'aaa', 'b' => 'bbb'));
}
}
$content = $this->twig->render('Admin/index.html.twig',$this->blocks);
return new \Symfony\Component\HttpFoundation\Response($content);
}
I know this is old, but if anyone is looking for something like this the SonataBlockBundle might be your solution.
https://github.com/sonata-project/SonataBlockBundle

How to var_dump variables in twig templates?

View layer pattern where you only present what you have been given is fine and all, but how do you know what is available? Is there a "list all defined variables" functionality in TWIG? Is there a way to dump a variable?
The solution I found by searching for it was to define a function where I can use my existing php debug tools by injecting a function, but all references I have found to that includes these nice two lines of code, but nowhere is it specified where to place them. Going by the fact that they need a $loader variable defined, I tried /app/config/autoload.php but the $loader there was the wrong kind. Where do I place the php code for adding a twig function?
As of Twig 1.5, the correct answer is to use the dump function. It is fully documented in the Twig documentation. Here is the documentation to enable this inside Symfony.
{{ dump(user) }}
If you are in an environment where you can't use the dump function (ex: opencart), you can try:
{{ my_variable | json_encode(constant('JSON_PRETTY_PRINT')) }}
You can use the debug tag, which is documented here.
{% debug expression.varname %}
Edit: As of Twig 1.5, this has been deprecated and replaced with the new dump function (note, it's now a function and no longer a tag). See also: The accepted answer above.
So I got it working, partly a bit hackish:
Set twig: debug: 1 in app/config/config.yml
Add this to config_dev.yml
services:
debug.twig.extension:
class: Twig_Extensions_Extension_Debug
tags: [{ name: 'twig.extension' }]
sudo rm -fr app/cache/dev
To use my own debug function instead of print_r(), I opened vendor/twig-extensions/lib/Twig/Extensions/Node/Debug.php and changed print_r( to d(
PS. I would still like to know how/where to grab the $twig environment to add filters and extensions.
If you are using Twig in your application as a component you can do this:
$twig = new Twig_Environment($loader, array(
'autoescape' => false
));
$twig->addFilter('var_dump', new Twig_Filter_Function('var_dump'));
Then in your templates:
{{ my_variable | var_dump }}
Dump all custom variables:
<h1>Variables passed to the view:</h1>
{% for key, value in _context %}
{% if key starts with '_' %}
{% else %}
<pre style="background: #eee">{{ key }}</pre>
{{ dump(value) }}
{% endif %}
{% endfor %}
You can use my plugin which will do that for you (an will nicely format the output):
Twig Dump Bar
If you are using Twig as a standalone component here's some example of how to enable debugging as it's unlikely the dump(variable) function will work straight out of the box
Standalone
This was found on the link provided by icode4food
$twig = new Twig_Environment($loader, array(
'debug' => true,
// ...
));
$twig->addExtension(new Twig_Extension_Debug());
Silex
$app->register(new \Silex\Provider\TwigServiceProvider(), array(
'debug' => true,
'twig.path' => __DIR__.'/views'
));
The complete recipe here for quicker reference (note that all the steps are mandatory):
1) when instantiating Twig, pass the debug option
$twig = new Twig_Environment(
$loader, ['debug'=>true, 'cache'=>false, /*other options */]
);
2) add the debug extension
$twig->addExtension(new \Twig_Extension_Debug());
3) Use it like #Hazarapet Tunanyan pointed out
{{ dump(MyVar) }}
or
{{ dump() }}
or
{{ dump(MyObject.MyPropertyName) }}
{{ dump() }} doesn't work for me. PHP chokes. Nesting level too deep I guess.
All you really need to debug Twig templates if you're using a debugger is an extension like this.
Then it's just a matter of setting a breakpoint and calling {{ inspect() }} wherever you need it. You get the same info as with {{ dump() }} but in your debugger.
Since Symfony >= 2.6, there is a nice VarDumper component, but it is not used by Twig's dump() function.
To overwrite it, we can create an extension:
In the following implementation, do not forget to replace namespaces.
Fuz/AppBundle/Resources/config/services.yml
parameters:
# ...
app.twig.debug_extension.class: Fuz\AppBundle\Twig\Extension\DebugExtension
services:
# ...
app.twig.debug_extension:
class: %app.twig.debug_extension.class%
arguments: []
tags:
- { name: twig.extension }
Fuz/AppBundle/Twig/Extension/DebugExtension.php
<?php
namespace Fuz\AppBundle\Twig\Extension;
class DebugExtension extends \Twig_Extension
{
public function getFunctions()
{
return array (
new \Twig_SimpleFunction('dump', array('Symfony\Component\VarDumper\VarDumper', 'dump')),
);
}
public function getName()
{
return 'FuzAppBundle:Debug';
}
}
For debugging Twig templates you can use the debug statement.
There you can set the debug setting explicitely.
You can edit
/vendor/twig/twig/lib/Twig/Extension/Debug.php
and change the var_dump() functions to \Doctrine\Common\Util\Debug::dump()
As most good PHP programmers like to use XDebug to actually step through running code and watch variables change in real-time, using dump() feels like a step back to the bad old days.
That's why I made a Twig Debug extension and put it on Github.
https://github.com/delboy1978uk/twig-debug
composer require delboy1978uk/twig-debug
Then add the extension. If you aren't using Symfony, like this:
<?php
use Del\Twig\DebugExtension;
/** #var $twig Twig_Environment */
$twig->addExtension(new DebugExtension());
If you are, like this in your services YAML config:
twig_debugger:
class: Del\Twig\DebugExtension
tags:
- { name: twig.extension }
Once registered, you can now do this anywhere in a twig template:
{{ breakpoint() }}
Now, you can use XDebug, execution will pause, and you can see all the properties of both the Context and the Environment.
Have fun! :-D
you can use dump function and print it like this
{{ dump(MyVar) }}
but there is one nice thing too, if you don't set any argument to dump function, it will print all variables are available, like
{{ dump() }}

Resources