MODx caches what it shouldn't - modx

I'm working with MODx revo. I wrote a snippet called putBoxId with the following content:
<?php
$id = isset($_GET['id']) ? $_GET['id'] : null;
if (!is_null($id)) {
return $modx->getChunk($tpl, array('id' => $id));
}
return '';
I use it like this: [[~3[[!putBoxId? &tpl='boxIdUrl']] ]] (with backticks, of course), where boxIdUrl is the chunk with the following content:
? &id=`[[+id]]`
The problem is, for some reason it gets cached. I tried putting '!' In all combinations, still gets cached. How can this be fixed?

The [[~3 is being cached, so your putBoxId is actually called only the first time.
In Revo - any *[[* (tag) can start with a ! (non-cacheable flag). So, in your case - [[!~3[[!putBoxId? &tpl='boxIdUrl']] ]] (note: there's a typo here and in your original question, see comment below. this should work: [[~3]][[!putBoxId? &tpl='boxIdUrl']])
more info here
Even better - unless there's a good reason, get rid of that chunk, as the $modx->getChunk call wouldn't be cached in your scenario (goes to db to get template, etc...).
Do it all in the snippet itself using modx->makeUrl (see link for more options)
<?php
$resourceId = $modx->getOption('resourceId', $properties, $modx->resource->get('id')); // get resourceId from snippet, default to current
$args = (!empty($_REQUEST['id']))? array('id'=>$_REQUEST['id']) : '';
return $modx->makeUrl($resourceId, '', $args);
Call like this:
[[!putBoxId]] or [[!putBoxId? &resourceId=`3`]]

Related

URL rewriting using NodeJS

I want to customize my URL rewriting but it seems not working as I'd like it to.
My old code :
var rewrite = require('express-urlrewrite');
exports.rewrite = function(app){
app.use(rewrite('/p/:id/:seoUrl', '/page/show/$1/$2'));
}
In my browser : http://mysite/p/1/seo-title (this URL works)
My new code :
var rewrite = require('express-urlrewrite');
exports.rewrite = function(app){
app.use(rewrite('/:seoUrl', '/page/show/$1/$2'));
}
In my browser : http://mysite/seo-title (ID not found)
Using NodeJS, is there a way to exclude the ID in the URL?
well. if you take a close look at this: '/page/show/$1/$2' you might notice that it accepts two arguments.
since you removed :id you'd have to replace $1 with a static id or remove it completely aswell as you have to change $2 to $1
so in the end your code might look like this: app.use(rewrite('/:seoUrl', '/page/show/1/$1'));
or like this: app.use(rewrite('/:seoUrl', '/page/show/$1'));

Chunk is called with unique data, but renders duplicate content

Guess my problem is closely related to this one : Snippet duplicates content when used multiple times on page
The elements of my problem are the following ...
$modx->loadedResources : an (empty) array registered in the main $modx object via a snippet on page load. The array holds resource id's of the resources fetched from the DB randomly, so the same resource isn't shown twice on the same page.
loadRandomResource : a snippet using XPDO-style querying to load a random resource from the DB. It uses $modx->parseChunk() to fill the placeholders in the chunk with the resource data. With each call, it appends the id of the fetched resource being fetched to the $modx->loadResources array.
I used some debugging to check if the resource id's were properly being stored in my array, each time I fetch a new random resource, which happens to be the case. I then checked if the db returns different results, each time I call the loadRandomResource snippet, and it does. I can also confirm that it doesn't return duplicate results (I exclude the already loaded resource ID's in my XPDO query).
However, when calling the snippet at 3 various locations throughout my page template, all 3 snippet calls render the same resource, which is weird, since my debug shows that unique data is being loaded from the DB, and being sent to the chunk for rendering.
Please find below both the snippet code, as well as the chunk mark-up.
Does anyone have any ideas? Any help is much appreciated!
loadRandomResource snippet
$criteria = $modx->newQuery('modResource');
$criteria->select(array('id','pagetitle'));
$criteria->sortby('RAND()');
$criteria->limit(1);
$whereOptions = array(
'parent' => 2,
'deleted' => false,
'hidemenu' => false,
'published' => true
);
if (!empty($modx->loadedResources)) {
$whereOptions['id:NOT IN'] = $modx->loadedResources;
}
$criteria->where($whereOptions);
$resources = $modx->getCollection('modResource', $criteria);
$output = '';
foreach ($resources as $resource) {
$fields = $resource->toArray();
$fields['tv.tvPersonalPicture'] = $resource->getTVValue('tvPersonalPicture');
$fields['tv.tvJobTitle'] = $resource->getTVValue('tvJobTitle');
$output .= $modx->parseChunk('cnkTeamListItem', $fields);
$modx->loadedResources[] = $fields['id'];
}
return $output;
cnkTeamListItem chunk
<div>
<img src="[[+tv.tvPersonalPicture]]" alt="[[+pagetitle]]" />
<h2>[[+pagetitle]]<br /><span>[[+tv.tvJobTitle]]</span></h2>
</div>
I found the answer myself, solution is a bit odd though ...
I was calling my custom snippet 3 times in my template, uncached. Each call though exactly looked the same ...
[[!loadRandomResource? &type='teammember']]
Even though I had the exclamation mark in place, still ModX was caching the call, within the same page request.
So when I added a random unique value to each of the 3 calls, the issue was solved.
Call 1 : [[!loadRandomResource? &type='teammember' &unique='123465']]
Call 2 : [[!loadRandomResource? &type='teammember' &unique='987654']]
Call 1 : [[!loadRandomResource? &type='teammember' &unique='666666']]
Don't know if this is a bug or a feature, but I thought that the exclamation mark prevented caching, both across different pageviews, as well as within the same page view. Anyhow, thx for helping.
I use this code for rendering chunks in snippents:
<?php
// get chunk or template
$tplRow = $modx->getOption('tplRow', $scriptProperties, '');
// get template
if (substr($tplRow, 0, 6) == "#CODE:") {
$tplRow = substr($tplRow, 6);
} elseif ($chunk = $modx->getObject('modChunk', array('name' => $tplRow), true)) {
$tplRow = $chunk->getContent();
} else {
$tplRow = false;
}
// render template
$field = array(); // your fields
if ($tplRow) {
$chunk = $modx->newObject('modChunk');
$chunk->setCacheable(false);
$chunk->setContent($tplRow);
$output[]= $chunk->process($fields);
} else {
$output[]= '<pre>' . print_r($fields, 1) . '</pre>';
}
You do realize you could have done this with getResources, don't you?
http://rtfm.modx.com/display/ADDON/getResources
&sortby=`RAND()`&limit=`1`

Paginator (Migration from Cake 1.3 to 2.0)

I am struggling with the paginator in Cakephp 2.0. While I am trying to migrate my application to 2.0 I cant find any solution to jump directly to the last page. In 1.3 it was quiet to do that from outside like this:
echo $this->Html->link(__('Flights'), array('controller' => 'flights',
'action' => 'index','page' => 'last'));
but this little trick putting 'page:last' in does not work anymore in 2.0. Of course there is a Paginator function called last, but this would only help if I would be already inside the app. My Problem is to access from an outside link directly the last page of the paginator.
This is the simple way:
echo $this->Paginator->last('Any text');
Other way to get the number of the last page is:
echo $this->Paginator->counter(array('format' => '{:pages}'));
Then you can use it to generate your link.
For more info:
http://book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#PaginatorHelper::last
Shortly after creating a bounty for this question I found the solution to MY problem using CakePHP 2.2.4. I was trying to accomplish the same task but instead using version 2.2.4 instead instead of 2.0. Basically if I had a link that looked like http://www.domain.com/articles/page:last that the controller's pagination method would know what page to go to and display the correct results (articles) for that page. For example, if I have 110 articles and the pagination limit is set to 25, by going to that URL it would display page 5 of 5, showing records 101-110. I also wanted the same capability if I go to “page:first”.
I needed to change my library file lib/Cake/Controller/Component/PaginatorComponent.php.
I changed
if (intval($page) < 1) {
$page = 1;
}
To
if ((intval($page) < 1 && $page != "last") || $page == "first") {
$page = 1;
}
I also added
if($page == "last"){
$page = $pageCount;
}
After the line
$pageCount = intval(ceil($count / $limit));
Christian Waschke, with this solution, you can use the same link helper exactly how you wrote it in your question. For me, the link helper looked like this
<?php echo $this->Html->link('Go to Last Page', array('controller' => 'articles', 'action' => 'index', 'page' => 'last')); ?>
You can 'calculate' the last page yourself if 'last' is passed as the page number;
I would discourage making modifications in the CakePHP library files as this will make it hard to perform upgrades in the future.
Basically, the PaginatorHelper uses viewVars that are calculated and set by the PaginatorComponent, as seen here: https://github.com/cakephp/cakephp/blob/master/lib/Cake/Controller/Component/PaginatorComponent.php#L212
You can replicate this in your action; for example:
public function index()
{
if (!empty($this->request->params['named']['page'])) {
switch($this->request->params['named']['page']) {
case 'first':
// replace the 'last' with actual number of the first page
$this->request->params['named']['page'] = 1;
break;
case 'last':
// calculate the last page
$limit = 10; // your limit here
$count = $this->Flight->find('count');
$pageCount = intval(ceil($count / $limit));
// replace the 'last' with actual number of the last page
$this->request->params['named']['page'] = $pageCount;
break;
}
}
// then, paginate as usual
$this->set('data', $this->paginate('Flight'));
}
To improve this, this logic should be moved to a separate method, or to a behavior. However; as seen above, it is not required to make modifications in the PaginatorComponent!
Also note that the 'find(count)' in my example does not take additional conditions, they should be added if required
If you have a look in the CakePHP 1.3 source for paginate(), the code above is comparable; https://github.com/cakephp/cakephp/blob/1.3/cake/libs/controller/controller.php#L1204

PHP. Write an anchor in the Smarty template. (Kohana 3 + KSmarty)

I'm learning Kohana 3.2.0 together with KSmarty for Kohana 3. I'd like to write an anchor on the page like this:
Page list
I can build the url in the controller and pass it to Smarty as a variable but. Is there a way to build the anchor or URL in Smarty template (including "http://www.mysite.cz" part)?
If it is not possible to build the anchor. Is it at least possible to build full URL?
The Reason: I have a main template which includes another template.
The main template will be used by multiple controllers and I would like to avoid building the URL in each controller. Therefore I'll be happy if KSmarty will be able to do it for me.
The only solution I have found is to write custom function. Save following code into function.url.php file in Smarty plugins directory:
function smarty_function_url($params, &$smarty)
{
$type = '';
if(isset($params['type'])) $type = $params['type'];
$protocol = 'http';
if(isset($params['protocol'])) $protocol = $params['protocol'];
$url = '';
if(isset($params['url'])) $url = $params['url'];
$text = '';
if(isset($params['text'])) $text = $params['text'];
switch($params['type'])
{
case 'url':
return Kohana_URL::site($url, $protocol);
case 'anchor':
$url = Kohana_URL::site($url, $protocol);
return "<a href='{$url}'>{$text}</a>";
default:
return Kohana_URL::base('http');
}
}
Examples of use in Smarty template:
{url}
{url type='url' url='admin/categories' protocol='https'}
{url type='anchor' url='admin/articles' text='List of articles'}
The first block in which variables are set I had to write otherwise Smarty was generating notice "Undefined variable...". I'm just PHP student, suggestions for code improvement are welcome.
Hope it will help the others.

How does one get Drupal's current view/page identifier?

What I am looking for is a page_id/view_id that I can use to identify and style specific pages. I would use the title or the url, but there is a chance that it could change if the a higher-up decides that the page should no longer be called Golf, but rather Tee-Time because he likes it better.
Presumably this identifier would not change if the current page were to be a paged view (page 1,2,3,4...).
One way of solving this is the following. It's depending on the url, so if it changes, so does the class-name.
In my themes template.php I implemented hook_preprocess_page:
function mytheme_preprocess_page(&$vars, $hook) {
$body_classes = array();
$body_classes[] = 'page-' . _get_page_name($_SERVER['REQUEST_URI']);
$vars['body_classes'] = implode(' ', $body_classes);
}
function _get_page_name($request_uri) {
static $numeric_subsection = array(
'/node/' => 'node',
);
$preAlias = $request_uri;
$alias = substr(strrchr($preAlias, "/"), 1);
if (strpos($alias, '?') > -1) {
$alias = substr($alias, 0, strpos($alias, '?'));
}
$page_name = $alias;
if (empty($alias)) {
$page_name = 'start';
}
else if (is_numeric($alias)) {
foreach ($numeric_subsection as $section => $pn) {
if (strpos($preAlias, $section) > -1) {
$page_name = $pn;
}
}
}
return $page_name;
}
Then in the main page-template:
<body class="<?php print $body_classes; ?>">
This isn't a generic solution. So you'll probably have to customize this for your specific needs. It will for example need som tweaking to play nicely with path auto.
This depends a little on how your site is put together (panel pages, view pages, "normal" pages). Essentially, you need to figure out what vars are in scope, and then determine which information in them can be used. To determine what is in scope, you can use print_r(array_keys(get_defined_vars())); and then poke around in the individual vars.
An option is to do something in theme_preprocess_page. One option is to get the page data via page_manager_get_current_page(), poke around in there, and then add body classes as needed. Without knowing what you are doing, you essentially need to print_r the results somewhere, look at what you have, and go from there.

Resources