I want to do something like this:
$app->mount('dashboard', new Travel\Controllers\Dashboard())->before(function() use ($app) {
//check if is logued...
})
Is it possible?
Thanks!
you can do
$controllers = $app["controllers_factory"];
$controllers->before(function(Request $request){});
in you ControllerProviderInterface::connect method
if you need a function defined in $app definition php file you can create a protected function
$app['callback'] = $app->protect(function(){});
then
$controllers->before($app["callback"]);
Related
I'm wanting to put a google analytics account number into the local or global.php for each update across the application. However, I can't figure out how to access it from the views. Am I going about this wrong, or is there a way to do this? What I want to avoid is putting things into every controller to pass it along. I just want the layouts to be able to grab it.
If there's a better solution to this, I'm all ears.
Thanks!
If you have just a code for all the pages, probably you can hardcode all the analytics code in your layout view, so it will be there for al the modules view.
If you dont want to hardcode it, or you dont want to have the code in all the pages, or you have a set of diferent layout files, then I think that the best you can do is to create a ViewHelper.
Ill try to explain it from the beginning, in case this is the first time you do this.
First, create a Module, i'd call it Utils.
in the modules src, you can create a folder Utils\View\Helper and there you create a file Analytics.php with the class Analytics, as follows:
<?php
namespace Utils\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\Mvc\Controller\Plugin\FlashMessenger as FlashMessenger;
class Analytics extends AbstractHelper
{
var $code = null;
public function setCode($code)
{
$this->code = $code;
}
public function __invoke()
{
ob_start();
?>
<!-- analytics-->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '<?=$this->code?>']);
_gaq.push(['_trackPageview']);
(function () {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = 'http://www.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
</script>
<!-- end analytics-->
<?php
return ob_get_clean();
}
}
?>
in your module.php create function getViewHelperConfig where you can define the factory for the viewhelper your about to create, likethis
public function getViewHelperConfig()
{
return array(
'factories' => array(
'analytics' => function($sm) {
$config = $sm->getServiceLocator()->get('Config');
//now in config, you have all your configurations (local, global, etc) as an asociative array
$add = new \Utils\View\Helper\Analytics();
//you asign here the code from your merged configuration
//(replace *analytics_account_number* with whatever you called it)
$add->setCode($config["analytics_account_number"]);
return $add;
}
));
}
Now, inside a view, you can simply call
echo $this->analytics();
and the framework will search the factory, create the object, asign the values, and call the invoke method, to return the full code to your view. And thats all. write once, run anywhere!
At present I set a couple of variables to be used by the app's overall layout.phtml, using the onDispatch method of a BaseController, which all my other controllers extend:
public function onDispatch(MvcEvent $e)
{
$config = $this->getServiceLocator()->get('config');
$this->layout()->setVariable('platformName', $config['platform']['name']);
$this->layout()->setVariable('platformYear', $config['platform']['year']);
}
This works fine, until I test some error pages and find that these pages do not get provided with the variables, as it's not using the base controller.
How can I get around this problem and provide the error pages with the same variables?
Change the event you're listening for.
In this case, I'd move this logic to the application bootstrap event or the application render event (I haven't tested this, but it would probably work fine).
One example, in your Module.php
public function onBootstrap($e)
{
$config = $e->getApplication()->getServiceManager()->get('config');
//$e->getViewModel()->setVariable();
}
Haven't tested that commented out line, but it should get you headed in the right direction.
EDIT: Found an example of using the render event
public function onBootstrap($e)
{
$event = $e->getApplication()->getEventManager();
$event->attach('render', function($e) {
$config = $e->getApplication()->getServiceManager()->get('config');
$e->getViewModel()->setVariable('test', 'test');
});
}
(Necro)
When using onDispatch in a Controller, remember to return the parent with the event and all:
public function onDispatch(MvcEvent $e)
{
// Your code
return parent::onDispatch($e);
}
Otherwise, the logic on your Actions in that Controller will be ignored.
Is it possible to access the current controller instance from within a TagLib? For example:
class FooTagLib {
static namespace = 'foo'
def msg = { attrs, body ->
// Can I get a reference to the current controller here?
}
}
I want to do this because I store some data in a property of the controller and want to access it within the TagLib. I realise this may sound strange, but just humour me....
Inside your msg tagLib:
grailsApplication.getArtefactByLogicalPropertyName('Controller', pageScope.controllerName)
Like Views, you have access to the current controller and action through controllerName and actionName
Try something like this...
def ctl = grailsApplication.getArtefactByLogicalPropertyName('Controller', 'whateverController')
In symfony, I call an action and I want this to return json to jQuery frontend.
The Jobeet tutorial teaches how to return a partial but I want to return json, not a partial.
If it's just a normal AJAX action you're returning it from, I think I've used the following somewhere in the past:
return $this->renderText(json_encode($something));
The cheap way:
function executeSomethingThatReturnsJson(){
$M = new Model();
$stuff = $M->getStuff();
echo json_encode($stuff);
die(); //don't do any view stuff
}
The smarter way:
A smarter way is to create a nice subclass of sfActions that helps handling json-stuff.
In a project I did recently, I created a application called 'api' (./symfony generate:application api)
and then created a file like:
api/lib/apiActions.class.php
<?PHP
class apiActions extends sfActions {
public function returnJson($data){
$this->data = $data;
if (sfConfig::get('sf_environment') == 'dev' && !$this->getRequest()->isXmlHttpRequest()){
$this->setLayout('json_debug');
$this->setTemplate('json_debug','main');
}else{
$this->getResponse()->setHttpHeader('Content-type','application/json');
$this->setLayout('json');
$this->setTemplate('json','main');
}
}
}
Notice that I explicitly set the template there.
So my jsonSuccess.php template is simply:
<?PHP echo json_encode($data);
While json_debugSuccess.php makes things prettier:
<?PHP var_dump($data); ?>
Then you can have a controller that extends apiActions (instead of the usual sfActions) that looks like this:
<?php
class myActions extends apiAction {
public function executeList(sfWebRequest $request)
{
$params = array();
if ($request->hasParameter('id')){
$id = $request->getParameter('id');
if (is_numeric($id)){
$params['id'] = $id;
}
}
$data = Doctrine::getTable('SomeTable')->findAll();
$this->returnJson($data);
}
}
Disclaimer: The code above is copy/pasted out of an app I have, but simplified. It's for illustrative purposes only -- but it should get you heading in the right direction.
FYI: In case of Symfony 2.x "quick and dirty" way looks like this:
return new Response(json_encode($data), 200, array('Content-Type', 'text/json'));
Return new JsonResponse(array);
I tried to use the Sub New but it I don't have access to the url information
what I have is something like:
function Index(byval lang as string) as action result
setLang(lang)
....
return view
end function
function List(byval lang as string) as action result
setLang(lang)
....
return view
end function
function Details(byval id as integer?, byval lang as string) as action result
setLang(lang)
....
return view
end function
.....
is there a generic way I could use so I don't have to deal with the language in EVERY action?
Override OnActionExecuting():
public class YourController : Controller
{
protected string Lang;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Lang = filterContext.ActionParameters["lang"];
/* OR */
Lang = filterContext.RouteData.Values["lang"];
}
...
}
It is better to override OnActionExecuting() in the base Controller if you have one in your project.
UPDATE:
You can remove "lang" from your route and from your actions and move it to query string:
<%= Html.ActionLink("text", "action", "controller", new { lang = "ru" }, null) %>
with "Default" route will produce:
/controller/action/id?lang=ru
Then in OnActionExecuting:
Lang = Request.QueryString["lang"];
You could try to look into Aspect-Oriented Programming (AOP) if you really want to do it the generic way, but I am not entirely sure its worth it in your case.
Random link on AOP: http://weblogs.asp.net/podwysocki/archive/2008/03/28/understanding-aop-in-net.aspx
I would create a custom action filter and decorate each action method with my custom [HandleLanguage] attribute.
The short answer is no.
If you find that you need to do the same thing constantly, you might want to re-think your architecture on a higher level.
If this were in Python I would think about using a function decorator. I see examples of doing this with C# but nothing for VB.NET. In this particular case though, I am not sure there is really any benefit.