Forward with another template - php

I'm facing a problem with the forward method of Symfony (v2.3).
Basicly, I have two controllers in two distinct bundles. Let's say DesktopBundle for a desktop version of the app, and MobileBundle for the mobile version.
I want to reuse code of an action of the DesktopBundle into an action of MobileBundle. What I do now is a forward :
DesktopController
namespace Acme\DesktopBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Route("/")
*/
class IndexController extends Controller
{
/**
* #Route("", name="desktopIndex")
* #Template()
*/
public function indexAction()
{
/* some code I don't want to duplicate */
return array(
'some' => 'var'
);
}
}
MobileController
namespace Acme\MobileBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Route("/")
*/
class IndexController extends Controller
{
/**
* #Route("", name="mobileIndex")
* #Template()
*/
public function indexAction()
{
return $this->forward('AcmeDesktopBundle:Index:index');
}
}
Now it works, but obviously the Response object is returned with the rendered template of the desktop version of the indexAction.
What I would like, is to get the variables and then render the template of the mobile version.
What I tried is to pass a variable into the forward method and then render the action conditionally into the desktop version:
return $this->forward(
'acmeDesktopBundle:Index:index',
array('mobile' => true)
);
This would work, but I don't really want to change to code inside the DesktopBundle but only the MobileBundle. Is there a way to achieve this ? I am missing something, or should I go to an entirely different solution ?

Forwarding means to redirect to the given page, but without changing the url on the client. I.e. redirect on the server side. If you want only access the return value of the action, simply call it. With the #Template annotation this is made very easy.
namespace Acme\MobileBundle\Controller;
use Acme\DesktopBundle\Controller\IndexController as DesktopController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Route("/")
*/
class IndexController extends Controller
{
/**
* #Route("", name="mobileIndex")
* #Template()
*/
public function indexAction()
{
$desktop = new DesktopController();
$desktop->setContainer($this->container);
$values = $desktop->indexAction();
// do something with it
return $values;
}
}

Related

Override protected method in Laravel Illuminate class

I'd like to override the following method in Laravel's Illuminate\Foundation\Vite class:
/**
* Generate a script tag for the given URL.
*
* #param string $url
* #return string
*/
protected function makeScriptTag($url)
{
return sprintf('<script type="module" src="%s"></script>', $url);
}
...by adding a "defer" attribute to the script tag. How would I go about doing this, as this is a protected function?
May be like that :
<?php
namespace myApp;
use Illuminate\Foundation\Vite as IllVite;
class myClass extends IllVite{
//...
protected function makeScriptTag($url){
return sprintf('<script type="module" src="%s" defer></script>', $url);
}
//...
}
In the controller(s) which call "Vite", change :
use Illuminate\Foundation\Vite;
by
use myApp\myClass;
The svgta is right, if you use that method in another place in your app.
But, if you want to change only that particular behavior, and not to use it in other places, then you can rewrite the original class and replace it by binding changed class to the app in app/Providers/AppServiceProvider:
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
'Illuminate\Foundation\Vite', // original class that will be replaced
'App\VendorRewrites\ViteChanged' // custom class that will be injected
);
}
............
Another post that can help: Laravel 6-7 How Can I Override/Change a Vendor Class?

How to work with Page Objects in laravel-dusk

I'm a new in a php and dusk, but I try to work with page object in dusk, and I'm stuck because when I try to add page object to test, phpstorm said me that "Method logInUserName not found in $this". Can someone explain to me where i'm wrong?
I have page class:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class LogInPage extends Page
{
/**
* Get the URL for the page.
*
* #return string
*/
public function url()
{
return '/login';
}
/**
*
* #return void
*/
public function logInUserName(Browser $browser)
{
$browser->type("#username", "lol");
}
}
I have test class
use Tests\Browser\Pages\LogInPage;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use PHPUnit\Framework\Assert;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* #return void
*/
public function testLogInFail()
{
$this->browse(function (Browser $browser) {
$browser
->visit(new LogInPage)
->logInUserName()
->keys("#password","lol")
->click("button.btn-primary"));}
Agree this is annoying, there are 2 ways you could get around this
Restart the chaining on the browser object, you may still get a warning about logInUserName but you get your code assist back, which I agree can be useful when still learning.
$browser
->visit(new LogInPage)
->logInUserName();
$browser
->keys("#password","lol")
->click("button.btn-primary"));
Create a helper file defining your custom functions
Or use this gist and create a file in the root of your project that your IDE will read - https://gist.github.com/slava-vishnyakov/5eb90352fc97702f53a41888e5bae27a
Only issue is you may get a PHPSTORM warning about multiple definitions exist for class Browser...not sure how to get around that
Results in something like this
<?php
namespace Laravel\Dusk {
class Browser
{
/**
* #return Browser
*/
public function logInUserName()
{
}
}
}

How to access current placeholder value?

Symfony 3.4.
I have annotations for my controller:
/**
*
* #Route("/{prefix}", requirements={"prefix":"daily_task|event"})
*/
class TaskController extends Controller
and want to access current {prefix} value directly from controller's methods (which aren't routed actions). How to get it's value?
Finally: $this->get('request_stack')->getCurrentRequest()->get('prefix')
Symfony will pass you the variables automatically if you use them as function parameters, like this:
/**
*
* #Route("/{prefix}", requirements={"prefix":"daily_task|event"})
*/
class TaskController extends Controller {
/**
* #Route("/{_locale}/some/path", name="_some_route_name")
*/
public function actualAction($prefix, $_locale) { /* ... */ }
}
Alternatively you can use the whole request like this:
/**
*
* #Route("/{prefix}", requirements={"prefix":"daily_task|event"})
*/
class TaskController extends Controller {
/**
* #Route("/{_locale}/some/path", name="_some_route_name")
*/
public function actualAction(Request $request) {
$prefix = $request->get('prefix');
}
}

How to access Sylius Services from Custom Controller

I have this Controller in a fresh sylius standard App and I am trying to access some service from the container but the container is always null.
According to the Symfony Docs, all you need to make your controller container aware is extend the Controller class, as I am doing.
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class HomepageController extends Controller
{
/**
* #var EngineInterface
*/
private $templatingEngine;
/**
* #param EngineInterface $templatingEngine
*/
public function __construct(EngineInterface $templatingEngine)
{
$this->templatingEngine = $templatingEngine;
}
/**
* #param Request $request
*
* #return Response
*/
public function indexAction(Request $request)
{
dump($this->get('sylius.factory.product'));
return $this->templatingEngine->renderResponse('#App/index.html.twig');
}
}
is there any additional configuration I need to do? Any help is welcome.

Extending Laravel base controller

I am a newbie in Laravel framework and I want to extend a base controller which in turn extends controller. However, I discovered that when I do that, my controller no longer recognises my session variables.
Here is my code
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends PermissionController
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
dd(session('userdata')['user_urls']);
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
And this is my PermissionController code
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PermissionController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct(Request $request) {
if(!session('userdata')['user_urls']->contains($request->path())){
dd(session('userdata')['user_urls']);
}
}
}
But I realize that my session('userdata')['user_urls'] becomes null at the PermissionController. But if I make FeeController to extend Controller, my session variables are intact.
I need to use the session variables for some control at the permission controller.
I am running Laravel 5.3 on a MAC OSX and PHP 7
I have figured out the problem. Actually, PermissionController is not registered in the web middleware group so that session is not persisting in the PermissionController. So the solution to your question is just make a trait named as Permission instead of the controller and use it in FeesContorller.
trait Permission{
public function permission(Request $request) {
if($request->session()->get('name') != null){
echo "Hello World";
}
}
}
And FeesController like this:
class FeesController extends Controller
{
use Permission;
public function index(Request $request)
{
$this->permission($request); // the method of the trait.
echo "\n".$request->session()->get('name');
}
}
Output:
If the name attribute is set in session then :
Hello World
Passion Infinite
Otherwise
No Output // null
I have solved the same problem with middleware. I have created a middleware that takes care of the authorization of requests by checking the session to ensure that the controller action being accessed is available in session.
This is the middleware
namespace App\Http\Middleware;
use Closure;
class PermissionMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$currentAction = \Route::currentRouteAction();
list($nothing,$route_action) = explode('App\Http\Controllers\\', $currentAction);
$user_actions=session('userdata')['user_urls'];
if((empty($user_actions))||!$user_actions->contains($route_action)){
return redirect('denied');
}
return $next($request);
}
}
This is the controller
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$data['title']='New Fee';
return view('settings.fee.create',$data);
}
So, instead of using the routes (cos of some other reasons), I used the controller actions.
So, once a user logs in, all the controller actions he can access are loaded into session. When he tries to perform any action, the middleware, does the check to ensure he is allowed to perform that action. Otherwise, he is routed away.
So, I either add 'permission' to the routes middleware or call
$this->middleware('permission')
on the controller's construct method.
That is working for me now.
Thank you everybody for your contributions.

Categories