Within the reentryAction in my CustomerclientController I want to forward into the indexAction in case of successful validity check of the post parameters.
Unfortunately, the forward doesn't work. While debugging, I determined that the reentryAction method will be called again, instead of indexAction.
I registered a Dispatcher in my services.php as follows:
$di->setShared('dispatcher', function() use ($eventsManager) {
$dispatcher = new MvcDispatcher();
// Bind the eventsManager to the view component
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
The CustomerclientController:
class CustomerclientController extends Controller {
public function reentryAction($hash) {
// ... a lot of code
if ($this->request->isPost()) {
// ... a lot of code
if ($valid) {
$this->dispatcher->forward([
"customerclient",
"index"
]);
return;
}
}
}
public function indexAction() {
//Does something wise
}
}
I defined no special routes and do not use a route.php file.
What am I doing wrong or what did I forget?
Thanks in advance for your help!
Are you sure you need use MvcDispatcher?
I checked my project and I am using Dispatcher
$di->set('dispatcher', function() use ($di) {
$dispatcher = new Dispatcher;
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
I hope it works!
First of all, try to return the dispatcher->forward(). Second, maybe write the keys in the array.
if ($valid)
return $this->dispatcher->forward([
"controller" => "customerclient",
"action" => "index"
]);
Hope that helps!
Related
Let's say I have a controller called TeamsController. Controller has following method, that returns all teams user has access to.
public function findAll(Request $request): JsonResponse
{
//...
}
Then I have bunch of other controllers with the same method. I would like to create a single route, that would work for all controllers, so I would not need to add a line for each controller every time I create a new controller.
I am unable to catch the controller name from URI. This is what I have tried.
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
// This works
//$router->get('teams', 'TeamsController#findAll');
// This just returns TeamsController#findAll string as a response
$router->get('{resource}', function ($resource) {
return ucfirst($resource) . 'Controller#findAll';
});
});
You return a string instead of calling a controller action:
I believe Laravel loads the controllers this way (not tested)
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
$router->get('{resource}', function ($resource) {
$app = app();
$controller = $app->make('\App\Http\Controllers\'. ucfirst($resource) . 'Controller');
return $controller->callAction('findAll', $parameters = array());
});
});
But again, I don't really think it's a good idea.
I have a doubt. I have been checking laracasts and they show some examples of passing variable(s) from router to a view:
Route::get('about', function() {
$people = ['Eduardo', 'Paola', 'Chancho'];
return view('about')->with('people', $people);
});
Route::get('about', function() {
$people = ['Eduardo', 'Paola', 'Carlos'];
return view('about')->withPeople($people);
});
The second example, I am not sure how Laravel handle it. I know it works I have test it, but which pattern they use? why is it possible to handle a dynamic variable.
Thanks in advance for your help!
The second one is handled by Laravel through php's __call magic method. This method redirects all methods that start with 'with' to the with method through this code in the Illuminate\View\View class:
public function __call($method, $parameters)
{
if (Str::startsWith($method, 'with')) {
return $this->with(Str::snake(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException("Method [$method] does not exist on view.");
}
As you can see if the method starts with 'with' (Str::startsWith($method, 'with'), Laravel redirects it to the with method return $this->with by taking the first param as the string that follows 'with' Str::snake(substr($method, 4)) and the second param as the first param that was passed $parameters[0]
Hope this helps!
Try this to pass data in view
Route::get('about', function() {
$data['people'] = ['Eduardo', 'Paola', 'Chancho'];
return view('about')->withdata($data);
});
Try this, it works.
Route::get('about', function() {
$people = ['Eduardo', 'Paola', 'Chancho'];
return view('about',compact('people'));
});
I want to prevent write all route in Laravel route.php,actually i follow MVC routing like this www.example.com/controller/action/p1/p2/p3
if you have any good idea give it to me,
i wrote this
$controller = ucfirst(Request::segment(1));
$controller = $controller . 'Controller';
$result=App::make('indexController')->ChechIfExistController($controller);
if($result){
if(Request::segment(2))
$action=Request::segment(2);
else
$action='index';
if(Request::segment(5))
Route::any('/{controller?}/{action?}/{p1?}/{p2?}/{p3?}',array('uses'=>$controller.'#'.$action));
else if(Request::segment(4))
Route::any('/{controller?}/{action?}/{p1?}/{p2?}',array('uses'=>$controller.'#'.$action));
else if(Request::segment(3))
Route::any('/{controller?}/{action?}/{p1?}',array('uses'=>$controller.'#'.$action));
else
Route::any('/{controller?}/{action?}',array('uses'=>$controller.'#'.$action));
} else{
echo '404';
EXIT;
}
but i don't know how to control and check controller and action in laravel to understand if it exist or not.
i need your help.
thanks a lot.
ifound it,this code fix the problem and check if action exist or not,but i would like to do that with laravel but it seems laravel does not have any thing for checking controller and actions
$controller=='Controller'?$controller='IndexController':$controller;
$controllers=new $controller ();
if(method_exists($controllers,$action)){...}
and in composer define my route,
that's all
routes.php
Route::controllers([
'auth' => 'Auth\AuthController',
]);
in AuthController you can do that:
// will be available as METHODNAME /auth/url/{one?}/{two?}/{three?}/{four?}/{five?}
public [methodName]Url($one, $two, $three, $four, $five)
{
//...
}
// for example POST /auth/register
public function postRegister(Request $request)
{
// ...
}
// GET /auth/login
public function getLogin()
{
//...
}
it's not documented, but you can see that in sources:
https://github.com/laravel/framework/blob/5.0/src%2FIlluminate%2FRouting%2FControllerInspector.php
https://github.com/laravel/framework/blob/5.0/src%2FIlluminate%2FRouting%2FRouter.php#L238
That can be done such way:
First we have to write static routes and after that, dynamic route which uses database.
routes.php
Route::get('/', function () {
return 'welcome';
});
Route::get('/faq', function () {
return 'faq';
});
Route::get('/about', function () {
return 'about';
});
Route::get('/{slug}', function ($slug) {
return Article::where('slug', $slug)->first();
});
An AJAX request to one of my controller actions currently returns the full page HTML.
I only want it to return the HTML (.phtml contents) for that particular action.
The following code poorly solves the problem by manually disabling the layout for the particular action:
$viewModel = new ViewModel();
$viewModel->setTerminal(true);
return $viewModel;
How can I make my application automatically disable the layout when an AJAX request is detected? Do I need to write a custom strategy for this? Any advice on how to do this is much appreciated.
Additionally, I've tried the following code in my app Module.php - it is detecting AJAX correctly but the setTerminal() is not disabling the layout.
public function onBootstrap(EventInterface $e)
{
$application = $e->getApplication();
$application->getEventManager()->attach('route', array($this, 'setLayout'), 100);
$this->setApplication($application);
$this->initPhpSettings($e);
$this->initSession($e);
$this->initTranslator($e);
$this->initAppDi($e);
}
public function setLayout(EventInterface $e)
{
$request = $e->getRequest();
$server = $request->getServer();
if ($request->isXmlHttpRequest()) {
$view_model = $e->getViewModel();
$view_model->setTerminal(true);
}
}
Thoughts?
Indeed the best thing would be to write another Strategy. There is a JsonStrategy which can auto-detect the accept header to automatically return Json-Format, but as with Ajax-Calls for fullpages, there it's good that it doesn't automatically do things, because you MAY want to get a full page. Above mentioned solution you mentioned would be the quick way to go.
When going for full speed, you'd only have one additional line. It's a best practice to always return fully qualified ViewModels from within your controller. Like:
public function indexAction()
{
$request = $this->getRequest();
$viewModel = new ViewModel();
$viewModel->setTemplate('module/controller/action');
$viewModel->setTerminal($request->isXmlHttpRequest());
return $viewModel->setVariables(array(
//list of vars
));
}
I think the problem is that you're calling setTerminal() on the view model $e->getViewModel() that is responsible for rendering the layout, not the action. You'll have to create a new view model, call setTerminal(true), and return it. I use a dedicated ajax controller so there's no need of determining whether the action is ajax or not:
use Zend\View\Model\ViewModel;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Controller\AbstractActionController;
class AjaxController extends AbstractActionController
{
protected $viewModel;
public function onDispatch(MvcEvent $mvcEvent)
{
$this->viewModel = new ViewModel; // Don't use $mvcEvent->getViewModel()!
$this->viewModel->setTemplate('ajax/response');
$this->viewModel->setTerminal(true); // Layout won't be rendered
return parent::onDispatch($mvcEvent);
}
public function someAjaxAction()
{
$this->viewModel->setVariable('response', 'success');
return $this->viewModel;
}
}
and in ajax/response.phtml simply the following:
<?= $this->response ?>
Here's the best solution (in my humble opinion). I've spent almost two days to figure it out. No one on the Internet posted about it so far I think.
public function onBootstrap(MvcEvent $e)
{
$eventManager= $e->getApplication()->getEventManager();
// The next two lines are from the Zend Skeleton Application found on git
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
// Hybrid view for ajax calls (disable layout for xmlHttpRequests)
$eventManager->getSharedManager()->attach('Zend\Mvc\Controller\AbstractController', MvcEvent::EVENT_DISPATCH, function(MvcEvent $event){
/**
* #var Request $request
*/
$request = $event->getRequest();
$viewModel = $event->getResult();
if($request->isXmlHttpRequest()) {
$viewModel->setTerminal(true);
}
return $viewModel;
}, -95);
}
I'm still not satisfied though. I would create a plugin as a listener and configure it via configuration file instead of onBootstrap method. But I'll let this for the next time =P
I replied to this question and seems it maybe similar - Access ViewModel variables on dispatch event
Attach an event callback to the dispatch event trigger. Once this event triggers it should allow you to obtain the result of the action method by calling $e->getResult(). In the case of an action returning a ViewModel it should allow you to do the setTerminal() modification.
aimfeld solution works for me, but in case some of you experiment issues with the location of the template, try to specify the module:
$this->viewModel->setTemplate('application/ajax/response');
The best is to use JsonModel which returns nice json and disable layout&view for you.
public function ajaxCallAction()
{
return new JsonModel(
[
'success' => true
]
);
}
I had this problem before and here is a quikc trick to solved that.
First of all, create an empty layout in your layout folder module/YourModule/view/layout/empty.phtml
You should only echo the view content in this layout this way <?php echo $this->content; ?>
Now In your Module.php set the controller layout to layout/empty for ajax request
namespace YourModule;
use Zend\Mvc\MvcEvent;
class Module {
public function onBootstrap(MvcEvent $e) {
$sharedEvents = $e->getApplication()->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
if ($e->getRequest()->isXmlHttpRequest()) {
$controller = $e->getTarget();
$controller->layout('layout/empty');
}
});
}
}
public function myAjaxAction()
{
....
// View - stuff that you returning usually in a case of non-ajax requests
View->setTerminal(true);
return View;
}
I'm trying to make urls translatable in my Silex app.
First, I tried overriding UrlGenerator and RedirectableUrlMatcher, but that didn't really work.
Then, I tried overriding:
$app['route_class'] = 'My\Translatable\Route';
with code like this:
class Route extends Silex\Route
{
public function setPattern($pattern)
{
return parent::setPattern(str_replace('admin', 'admin2', $pattern));
}
}
But I'm getting https://gist.github.com/6c60ef4b2d8d6584eaa7.
What is the right way to achieve this?
So the solution is to extend RedirectableUrlMatcher and overwrite match method instead of Route.
Matcher.php
class Matcher extends Silex\RedirectableUrlMatcher
{
public function match($pathInfo)
{
return parent::match(str_replace('/admin', '/', $pathInfo));
}
}
app.php
$app['url_matcher'] = $app->share(function () use ($app) {
return new Matcher($app['routes'], $app['request_context']);
});
Now when I'm accessing http://domain.com/admin silex returns content for http://domain.com/.
Hope this is what you need.