Get variables from different controllers in Silex 2 - silex

Making first project on Silex 2.
Don't know how to make a variable from one controller available for other controller.
$app -> get('links', function() use ($app) {
$foo="foo";
})
->bind('a1');
$app -> get ('/links/result/', function() use ($app) {
echo $foo;
})
->bind('b2');
How to make $foo visible for "b2"?

If you need to do something in two controllers, best make it a service; then it's available in both. Here's the Silex docs on service creation.
You'll need to create a class first:
class MyFirstService
{
public function getFoo()
{
return "foo";
}
}
Then register it as a (shared) service:
$app["my-first-service"] = $app->share(function () {
return new MyFirstService();
});
Finally you can use it:
$app->get('links', function() use ($app) {
$foo = $app["my-first-service"]->getFoo();
})->bind('a1');
$app->get ('/links/result/', function() use ($app) {
$foo = $app["my-first-service"]->getFoo();
})->bind('b2');
The above linked documentation page also tells how you can access other services in yours.

since you are using:
function() use ($app) {
in controller closures - you can use $app as a global variable container like:
$app['my_vars']['foo']='bar';
In a perfect way you should use data modal class for a variable storage.

Related

How to access a Stimulus JS controller method from inside a nested function?

I have a Stimulus controller inside which I have a setSegments function and then this code in the connect() method:
connect() {
const options = {
overview: {
container: document.getElementById('overview-container'),
waveformColor: 'blue',
},
mediaElement: document.querySelector('audio'),
dataUri: {
arraybuffer: document.getElementById('normal-audio-button').dataset.waveform
},
emitCueEvents: true,
};
Peaks.init(options, function (err, peaks) {
window.instance = peaks;
window.speed = "normal";
setSegments()
instance.on('segments.enter', function (segment) {
const segmentCard = document.getElementById(segment.id)
segmentCard.focus({preventScroll: true})
window.currentSegment = segment
});
});
}
setSegments() {
alert("segment set up)
}
I'm tryng to call setSegments() inside the Peaks.init function but it doesn't work because of the function's scope. I'm just not sure how to get around this. I tried calling this.setSegments() instead but it doesn't help.
What's the correct way of accessing the function in this case?
Thanks
The problem is that this is a bit confusing when working with JavaScript, however a way to think about it that it is the current context.
For example, when your code is running in the browser console or not in another function this is the global window object. When you are directly in the controller's connect method this is the controller's instance.
However, when you pass a function to Peaks.init that function creates it's own new context where this is the function's context and no longer the controller instance.
There are three common workarounds to calling this.setSegments;
1. Set a variable that is outside the function scope
As per your solution, const setSegments = this.setSegments; works because you are creating a reference outside the function scope and functions have access to this.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const setSegments = this setSegments;
Peaks.init(options, function (err, peaks) {
// this is the peaks init handler context
window.instance = peaks;
// this.setSegments(): - will not work
setSegments();
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
});
}
2. Use bind to override the function'sthis
You can pull your function out to a variable and then add .bind(this) to it so that when the function is called it will use the this from the controller instance instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const myFunction = function (err, peaks) {
// this is the BOUND this provided by the bind command and will be the controller's instance
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
};
myFunction.bind(this);
Peaks.init(options, myFunction);
}
3. Use an arrow function (easiest)
You should be able to use an arrow function in modern browsers or if you have a build tool running it may transpiled this for older browsers.
Instead of function() {} you use () => {} and it grabs the this from the parent function context instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
Peaks.init(options, (err, peaks) => {
// this is now the controller's instance and NOT the peak handler context
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually) and is NOT the controller instance as arrow function not used here.
});
});
}
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this for more details
I don't know if it's the best way to do it but adding the following right after the beginning of the connect method did the trick:
let setSegments = this.setSegments

Vaadin 14: sending data from a web component to server

How can i send data from client to server using html5 webcomponent
setting up data from server to client, is very easy, works like a charm
how ever cannot find solution to send data to server
Please assist, but Iam not going to use Lit or Polymer
#JavaScript
class SimpleComponent extends HtmlElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>";
this._input = this.querySelector('#test');
this._input.onchange = function() {
***** i want to send the value to server ****
})
}
setInputValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com",SimpleComponent);
Now Java at Server
#Tag("simple-com")
class SimpleComponent extends Component {
public SimpleComponent() {
}
public void setValue(String value) {
getElement().callJsFunction("setValue",value);
}
}
The main challenge compared to Polymer or LitElement is that an event handler defined using the pattern innerElement.onchange = function() {} will not be run with this referencing the custom element instance. This in turn means that trying to use this.$server won't work because this isn't pointing to the expected value even though $server is indeed present in the place where it's supposed to be.
The easiest way of fixing this is to change the code to use an arrow function (() => {}) instead of an explicit function. This works because arrow functions inherit this from the scope where the function is defined whereas explicit functions have this defined in different ways depending on how it is run. Another approach would be to store a reference to this in a separate variable (e.g. let root = this) and then reference that variable instead of this in the function (e.g root.$server.doSomething()).
Putting everything together, this is what the code looks like with my modifications to make everything work.
class SimpleComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = '<input type="text" id="test"/>';
this._input = this.querySelector('#test');
this._input.onchange = () => {
this.$server.handleChange(this._input.value);
};
}
setValue(value) {
this._input.value = value;
}
}
customElements.define("simple-com", SimpleComponent);

How to write tests using the service scope

My app is accessing object from the service scope (package:gcloud/service_scope.dart), like the storageService and additional services that I put inside the scope with ss.register().
Now I want to unit test a function that accesses this scope, and uses mock objects that I want to put in the service scope.
Is the only way to do so, to register them for every test, like this:
var withServiceScope = (callback()) => ss.fork(() {
// Register all services here
return callback();
});
test('the description', () => withServiceScope(() async {
// Call my function that can now access the service scope
}));
Or is there are way that allows me to do that in the setUp() function so I don't need to add this line for each test?
This might make it simpler to write your tests (code not tested)
import 'package:test/test.dart' as t;
import 'package:test/test.dart' show group;
var withServiceScope = (callback()) => ss.fork(() {
// Register all services here
return callback();
});
test(String description, Function testFunction) {
t.test(description, () => withServiceScope(() async {
testFunction();
}));
}
main() {
test('the description', () async {
// Call my function that can now access the service scope
}));
}

Why are my generator methods not inherited?

I'm trying to make a generator that I can then extend to form similar sub-generators
Here's my base generator:
var generators = require('yeoman-generator');
var VolumeAdderBase = module.exports = generators.Base.extend({
initializing: function() {
/* ... */
},
prompting: function () {
/* ... */
},
writing: function () {
/* ... */
}
});
Here's an example sub-generator:
var VolumeAdderBase = require('../../utils/VolumeAdderBase.js');
// console.log(VolumeAdderBase);
module.exports = VolumeAdderBase.extend({
fileType: "tomcat script",
containerName: "tomcat",
containerVolumeLocation: "/opt/tomcat/client-conf/"
});
When I try to run my sub-generator, it does nothing at all. No errors, no nothing.
When I dump the VolumeAdderBase object, there are plenty of methods on there, but they are all the Base ones. The ones defined in VolumeAdderBase are missing.
Am I missing something here? Or is there a better way to create similar sub-generators?
yeoman-generator is only going to run top level methods (Object.getOwnPropertyNames(prototype)). It doesn't go deeper in the prototype; that's by design. If Yeoman was to dig in the prototype, you couldn't use methods like this.destinationPath() or any other helpers as they'd all be schedule to be run - which would just break.
We have plans to support mixin in the future. But that's not currently the case.
As a fix, you can manually assign these methods:
VolumeAdderBase.prototype.prompting = VolumeAdderBase.prototype.prompting;
// etc...

ZF2: How to attach listener on the event in the Module class?

I want to set a basePath to be the same for every component of my Mvc for a given request. I mean when I call these methods I want to get the same result, lets say '/spam/ham/':
echo $this->headLink()->prependStylesheet($this->basePath() . '/styles.css') // $this->basePath() has to be '/spam/ham/'
$this->getServiceLocator()
->get('viewhelpermanager')
->get('headLink')
->rependStylesheet($this->getRequest()->getBasePath() . '/styles.css') // $this->setRequest()->getBasePath() has to be /spam/ham/
How to set the basePath for the first case I have found already, here's my question. By the way, the original manual doesn't have any info I received from the answer.
And now the second one - the basePath has to be set in the Request:
$this->getRequest()->getBasePath()
Here I found some answer that in fact doesn't work at all http://zend-framework-community.634137.n4.nabble.com/Setting-the-base-url-in-ZF2-MVC-td3946284.html. As said here StaticEventManager is deprecated so I changed it with SharedEventManager :
// In my Application\Module.php
namespace Application;
use Zend\EventManager\SharedEventManager
class Module {
public function init() {
$events = new SharedEventManager();
$events->attach('bootstrap', 'bootstrap', array($this, 'registerBasePath'));
}
public function registerBasePath($e) {
$modules = $e->getParam('modules');
$config = $modules->getMergedConfig();
$app = $e->getParam('application');
$request = $app->getRequest();
$request->setBasePath($config->base_path);
}
}
}
And in my modules/Application/configs/module.config.php I add:
'base_path' => '/spam/ham/'
But it desn't work. The problems are:
1) The run never comes to the registerBasePath function. But it has to. I've attached an event with the listener in the init function.
2) When I change SharedEventManager for just EventManager it happens to come to the registerBasePath function but an exeption is thrown:
Fatal error: Call to undefined method Zend\EventManager\EventManager::getParam()
What do I do wrong? Why the run of the program doesn't come to the registerBasePath function? If this is the only way to set the basePath globally then how to do it right?
I know the documentation is lacking of these kinds of things. But you are right in the way to approach this:
Be early (so at bootstrap)
Grab the request from the application
Set the base path in the request
The docs are lacking this information and the post you refer to is quite old. The fastest and easiest way to do this is using the onBootstrap() method:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$app->getRequest()->setBasePath('/foo/bar');
}
}
If you want to grab the base path from your config, you can load the service manager there:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$path = $config->base_path;
$app->getRequest()->setBasePath($path);
}
}

Resources