MODx Revo setTvValue returns old data - modx

$modx -> resource -> setTVValue(11, 1);
print_r($modx -> resource -> getTVValue(11));
$modx -> resource -> setTVValue(11, 2);
print_r($modx -> resource -> getTVValue(11));
I have a snippet that outputs 2 and 2, whereas it should output 1 and 2. Resource caching is turned off; snippet call is not cached either.
I have tried to fix this problem by another way, but it still updates my TV only after the whole page gets reloaded:
$tv = $modx->getObject('modTemplateVar',array('id'=>'11'));
$tv -> setValue($modx->resource->get('id'), 88);
$tv->save();
print_r($modx -> resource -> getTVValue(11));
By the way, if I am not working with TVs, everything is fine!
$modx -> resource -> set("pagetitle", 1);
print_r($modx -> resource -> get("pagetitle"));
$modx -> resource -> set("pagetitle", 2);
print_r($modx -> resource -> get("pagetitle"));
How do I fix this issue with TVs? I've tried to clear cache like this $modx->cacheManager->refresh(); too, but it didn't do the trick.

Ok try this
$id_resource = $modx->resource->get('id');
$id_tv = 11;
$value = 88;
$tv = $modx->getObject('modTemplateVar',array('id'=>$id_tv));
$tv -> setValue($id_resource, $value);
$tv->save();
if you need to get resource try this
$id_resource = $modx->resource->get('id');
$id_tv = 11;
$res = $modx->getObject('modResource',array('id'=>$id_resource));
print_r($res->getTVValue($id_tv));

You are going to love this:
$changeit = 11;
//$changeit= 'templateVarName';
$r = $modx->getObject('modResource', 177);
// or $r = $modx->resource
$tvs = $r->getTemplateVars();
if ($tvs) {
foreach ($tvs as $object){
if (is_object($object) && $object instanceof modTemplateVar){
print_r($object->toArray());
}
}
}
$r->setTVValue($changeit,'99999fhfhg');
echo '<hr>'. $r->getTVValue($changeit);
$r->setTVValue($changeit,'888885454564');
echo '<hr>'. $r->getTVValue($changeit);
$r->setTVValue($changeit,'123456789');
echo '<hr>'. $r->getTVValue($changeit);
By sending it
$changeit = '11';
It becomes a string and is_string is true and thereby processes the request as if the name is 11, not the ID. You can send either the id or the name of the TV. I personally use only names, as it is much easier to deal with later.
The code I placed works and was tested.
I will be filing a bug report on this, because it should be a tad cleaner.
Also, you retrieve the current resource, update it etc. But you do not reload a "fresh" version of the resource after it is updated. You are in affect looking at the same var at the same state twice.
The mod->resource is the same as when you entered the page.
By making it a var it gets updated as you process through your changes.

Related

How to multi line string in terraform

I am trying below from an example
resource "google_logging_metric" "my_metric" {
description = "Check for logs of some cron job\t"
name = "mycj-logs"
filter = "resource.type=\"k8s_container\" AND resource.labels.cluster_name=\"${local.k8s_name}\" AND resource.labels.namespace_name=\"workable\" AND resource.labels.container_name=\"mycontainer-cronjob\" \nresource.labels.pod_name:\"my-pod\""
project = "${data.terraform_remote_state.gke_k8s_env.project_id}"
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
}
}
Is there a way to make the filter field multiline?
A quick search in Google sends you to the documentation: https://www.terraform.io/docs/language/expressions/strings.html#heredoc-strings
You just need to write something like
<<EOT
hello
world
EOT
If it's a matter of formatting the output, this answer covers it.
If you want to make your code more readable, i.e. split the long string over a few lines but keep it as a single line in the output, using the join() function might be worth considering:
resource "google_logging_metric" "my_metric" {
description = "Check for logs of some cron job\t"
name = "mycj-logs"
project = "${data.terraform_remote_state.gke_k8s_env.project_id}"
filter = join(" AND ",
[
"resource.type=\"k8s_container\"",
"resource.labels.cluster_name=\"${local.k8s_name}\"",
"resource.labels.namespace_name=\"workable\"",
"resource.labels.container_name=\"mycontainer-cronjob\"",
"resource.labels.pod_name:\"my-pod\""
]
)
metric_descriptor {
metric_kind = "DELTA"
value_type = "INT64"
}
}
Note that setting out the code this way shows that in the OP there is a missing AND in the filter expression.
Because the original expression is one long line, this is very hard to see and slow to read/maintain-- and mistakes are easy to make.

Spring Integration aggregator's release strategy based on last modified

I'm trying to implement the following scenario:
I get a bunch of files that have common file pattern, i.e. doc0001_page0001, doc0001_page0002, doc0001_page0003, doc0002_page0001 (where doc0001 would be one document consisting of 3 pages that I would need to merge, doc0002 would only have 1 page)
I want to aggregate them in a way that I will release a group only if all of the files for specific document are gathered (doc0001 after 3 files were picked up, doc0002 after 1 file)
My idea was to read the files in an alphabetical order and wait for 2 seconds after a group was last modified to release it (g.getLastModified() is smaller than the current time minus 2 seconds)
I've tried the following without success:
return IntegrationFlows.from(Files.inboundAdapter(tmpDir.getRoot())
.patternFilter("*.json")
.useWatchService(true)
.watchEvents(FileReadingMessageSource.WatchEventType.CREATE,
FileReadingMessageSource.WatchEventType.MODIFY),
e -> e.poller(Pollers.fixedDelay(100)
.errorChannel("filePollingErrorChannel")))
.enrichHeaders(h -> h.headerExpression("CORRELATION_PATTERN", "headers[" + FileHeaders.FILENAME + "].substring(0,7)")) // docxxxx.length()
.aggregate(a -> a.correlationExpression("headers['CORRELATION_PATTERN']")
.releaseStrategy(g -> g.getLastModified() < System.currentTimeMillis() - 2000)) .channel(MessageChannels.queue("fileReadingResultChannel"))
.get();
Changing the release strategy to the following also didn't work:
.aggregate(a -> a.correlationExpression("headers['CORRELATION_PATTERN']")
.releaseStrategy(g -> {
Stream<Message<?>> stream = g.getMessages()
.stream();
Long timestamp = (Long) stream.skip(stream.count() - 1)
.findFirst()
.get()
.getHeaders()
.get(MessageHeaders.TIMESTAMP);
System.out.println("Timestamp: " + timestamp);
return timestamp.longValue() < System.currentTimeMillis() - 2000;
}))
Am I misunderstanding the release strategy concept?
Also, is it possible to print something out from the releaseStrategy block? I wanted to compare the timestamp (see System.out.println("Timestamp: " + timestamp);)
Right, since you don't know the whole sequence for message group, you don't have any other choice unless to use a groupTimeout. The regular releaseStrategy works only when a message arrives to the aggregator. Since at the point of one message you don't have enough info to release the group, it is going to sit in the group store forever.
The groupTimeout option has been introduced to the aggregator especially for this kind of use-cases when we definitely would like to release a group without enough messages to group normally.
You may consider to use a groupTimeoutExpression instead of constant-based groupTimeout. The MessageGroup is a root evaluation context object for SpEL, so you will be able to get access to the mentioned lastModified for it.
The .sendPartialResultOnExpiry(true) is right option to deal with here.
See more info in the docs: https://docs.spring.io/spring-integration/reference/html/#agg-and-group-to
I found a solution to that with a different approach. I still don't understand why the above one wasn't working.
I've also found a cleaner way of defining the correlation function.
IntegrationFlows.from(Files.inboundAdapter(tmpDir.getRoot())
.patternFilter("*.json")
.useWatchService(true)
.watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.MODIFY), e -> e
.poller(Pollers.fixedDelay(100)))
.enrichHeaders(h -> h.headerFunction(IntegrationMessageHeaderAccessor.CORRELATION_ID, m -> ((String) m
.getHeaders()
.get(FileHeaders.FILENAME)).substring(0, 17)))
.aggregate(a -> a.groupTimeout(2000)
.sendPartialResultOnExpiry(true))
.channel(MessageChannels.queue("fileReadingResultChannel"))
.get();

tvOS shouldWaitForLoadingOfRequestedResource requesting the same resources

I'm implementing shouldWaitForLoadingOfRequestedResource handler for AVPlayer/AVURLAsset HLS videos and found a weird behavior in tvOS.
As I see it could request the same resources multiple times, including "root" manifest, second-level manifests and segments (and I'm talking not about multiple quality switches, it's requesting exactly the same resources).
In the same time, each request are served with my code well enough – video is playing good.
Also, exactly the same code is working fine in iOS – no duplicated requests.
In which cases AVURLAsset/AVAssetResourceLoader could request the same resources multiple times in tvOS?
I have the same problem
I can add that I'm using the apple sample app
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
print("\(#function) was called in AssetLoaderDelegate with loadingRequest: \(loadingRequest)")
var ret : Bool = true
ret = shouldLoadOrRenewRequestedResource(resourceLoadingRequest: loadingRequest)
return ret
}
This is the debug print i get:
resourceLoader(_:shouldWaitForLoadingOfRequestedResource:) was called
in AssetLoaderDelegate with loadingRequest:
{ URL:
skd://817015000008100f172b492d3b25f5dda31c59d090b21000 }, request
ID = 3, content information request =
AVAssetResourceLoadingContentInformationRequest: 0x14f6dd070, content
type = "(null)", content length = 0, byte range access supported = NO,
disk caching permitted = NO, renewal date = (null), data request =
AVAssetResourceLoadingDataRequest: 0x14f67ae50, requested offset = 0,
requested length = 9223372036854775807, requests all data to end of
resource = YES, current offset = 0
I can see each time the value request ID in the print is different

The ability to create Doc element of hypertext in Websharper.UI.Next

I have the string with html markup, an I want to cretae Doc elment from it like this:
Doc.FromHtm "<div><p>.....</p>.....</div>"
As I understand that this is not possible right now. Ok, what is not possible to accurately sew, I tried to roughly nail using jquery:
JQuery.JQuery.Of( "." + class'name ).First().Html(html'content)
But to call this code, I need to specify an event handler for the Doc element. But it is not implemented in UI.Next.
I tried to track changes of a model with a given CSS class asynchronously:
let inbox'post'after'render = MailboxProcessor.Start(fun agent ->
let rec loop (ids'contents : Map<int,string>) : Async<unit> = async {
// try to recive event with new portion of data
let! new'ids'contents = agent.TryReceive 100
// calculate the state of the agent
let ids'contents =
// merge Map's
( match new'ids'contents with
| None -> ids'contents
| Some (new'ids'contents) ->
new'ids'contents # (Map.toList ids'contents)
|> Map.ofList )
|> Map.filter( fun id content ->
// calculate CSS class name
let class'name = post'text'view'class'name id
// change it's contents of html
JQuery.JQuery.Of( "." + class'name ).First().Html(content).Size() = 0)
// accept the state of the agent
return! loop ids'contents }
loop Map.empty )
and then, for example for one element:
inbox'post'after'render.Post [id, content]
But it is too difficult, unreliable and not really working.
Please give me an idea how to solve the problem if possible. Thanks in advance!
Just in case someone needs to use static HTML in WebSharper on the server (I needed to add some javascript to the WebSharper generated HTML page), there is fairly new Doc.Verbatim usable e.g. like
let Main ctx action title body =
Content.Page(
MainTemplate.Doc(
title = title,
menubar = MenuBar ctx action,
body = body,
my_scripts = [ Doc.Verbatim JavaScript.Content ]
)
)
Already answered this on https://github.com/intellifactory/websharper.ui.next/issues/22 but copying my answer here:
If all you want is to create a UI.Next Doc from static html you can do the following:
let htmlElem = JQuery.JQuery.Of("<div>hello</div>").Get(0)
let doc = Doc.Static (htmlElem :?> _)
This is not very nice but should work and I don't think there's a better way to do it at the moment. Or maybe you could use templating but that's not documented yet and I'm not sure it would fit your use case.
Obviously if you want to change the rendered element dynamically you can make it a Var and use Doc.EmbedView together with Doc.Static.

How to store changes to a page in tornado.no/cms?

In a controller for a page in tornado-cms, I do the following:
def res = Service.tornado.articles([ articleCategoryPath: "boker/ny"]);
Service.tornado.loadFullArticles(res);
res.sort { a,b ->
b.props.year <=> a.props.year
}
tornado.small_articles = res;
Or, shorter:
tornado.small_articles = Service.tornado.articles([
articleCategoryPath: "boker/ny",
full: true ])
.sort { a, b -> b.props.year <=> a.props.year };
This fills the content box small_articles with the all the articles from a specific folder "boker/ny" reversely sorted by the article prop year.
It works fine, but is it possible to save the changes made to the content box tornado.small_articles so that the resulting list of articles is also visible from the GUI? Something like Service.tornado.saveChangesToPageContentBox(page, content_box_nr, tornado.small_articles);?
Start by removing the articles currently bound to the small_articles box like this:
Integer containerId = <id-of-small-articles-container>;
Service.tornado.getPageBindings(page.id).each { binding ->
if (binding.containerId == containerId)
Service.tornado.deletePageBinding(binding);
}
Then add new bindings for the articles you have collected:
tornado.small_articles.each {
Service.tornado.addPageBinding(new ArticlePageContainer(page.id, it.id, containerId));
}
You should not do this on every request to the given page, but rather update the list when the content changes or by some other, less frequent criteria.

Resources