ZF2 - same view file for multiple actions in a Controller - php

Im using ZF2 and I need to render same view (html page) in both add and edit actions. Is there a way to do it in ZF2 ?

In your controller, you can set the view script that will be rendered:
function someAction()
{
$result = new ViewModel();
$result->setTemplate('somemodule/somecontroller/arbitraryscript');
return $result;
}

And if you want to set one template for all Actions just rewrite your construtor methode:
<?php
namespace MyModel\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class IndexController extends AbstractActionController
{
/**
* #var ViewModel
* #access protected
*/
protected $viewModel;
public function __construct()
{
$this->viewModel = new ViewModel();
$this->viewModel->setTemplate('MyModel/index/default.phtml');
}
public function indexAction()
{
$this->viewModel->setVariables(array(
'message' => 'Hello indexAction()'
));
return $this->viewModel;
}
public function otherAction()
{
return $this->viewModel->setVariables(array(
'message' => 'Hello otherAction()'
));
}
}

Related

Php override construction error in extends controller mvc structure

In php mvc structure I have this base controller class and add the constructor like this :
namespace App\Core;
/**
* Controller class
*/
class Controller
{
/** #var View View The view object */
public $View;
public $templates;
public $app;
/**
* Construct the (base) controller. This happens when a real controller is constructed, like in
* the constructor of IndexController when it says: parent::__construct();
*/
public function __construct()
{
$this->app = \App\Core\System\App::instance();
$this->Language = new Language('en-gb');
$this->templates = new \League\Plates\Engine(Config::get('PATH_VIEW'));
$this->Url = new \App\Core\Url(Config::get('URL'),Config::get('URL'));
}
public function loadModel($name) {
$path = '\App\Catalog\Model\\'.$name;
$this->model = new $path;
return $this->model;
}
public function loadController($name) {
$path = '\App\Catalog\Controller\\'.$name;
$this->controller = new $path;
return $this->controller;
}
}
Now in action (ie edit account) controller i have :
namespace App\Catalog\Controller\Account;
use App\Core\Config;
use App\Core\Csrf;
use App\Core\Response;
use App\Core\Session;
class EditAccount extends \App\Core\Controller
{
public function __construct()
{
parent::__construct();
//Auth::checkAuthentication();
}
public function index()
{
}
public function action()
{
}
}
Now, I work in PhpStorm and see this override error:
How do can in Fix this error?
Note: If I remove extends \App\Core\Controller from EditAccount class, error fixed But I need to extends \App\Core\Controller.

Laravel 5.4: Class 'App\Http\Controllers\Response' not found error

I am following the Laracast's API tutorial and trying to create an ApiController that all the other controllers extend. ApiController is responsible for response handling.
class ApiController extends Controller
{
protected $statusCode;
public function getStatusCode()
{
return $this->statusCode;
}
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
}
public function respondNotFound($message = 'Not Found!')
{
return Reponse::json([
'error' => [
'message' => $message,
'status_code' => $this->getStatusCode()
]
]);
}
}
And i also have a ReportController that extends ApiController.
class ReportController extends ApiController
{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$report = Report::find($id);
if (! $report ) {
$this->respondNotFound(Report does not exist.');
}
return Response::json([
'data'=> $this->ReportTransformer->transform($report)
], 200);
}
}
When i try to call respondNotFound method from ReportController i get
Class 'App\Http\Controllers\Response' not found error
eventhough i add use Illuminate\Support\Facades\Response;to parent or child class i get the error. How can i fix this ?
Any help would be appreciated.
Since it's a facade, add this:
use Response;
Or use full namespace:
return \Response::json(...);
Or just use helper:
return response()->json(...);

Slim3 Container good practice?

Hello im learning PHP and i'am Building a REST API with the Slim3 Framework. I Create Routes Like this:
$container['HomeController'] = function () {
return new HomeController();
};
$currentContainer = CurrentContainer::getInstance();
$currentContainer->setContainer($container);
$app->get('/', 'HomeController:index')->setName("index");
My Problem was i had to pass the $container to every Single Controller Class iv'e created, because i need the container context in the Controller for routing etc.
then im build a Singleton Container Class like this:
class CurrentContainer
{
private static $instance;
private $container;
private function __construct()
{
}
private function __clone()
{
}
public static function getInstance()
{
if (self::$instance == null) {
self::$instance = new CurrentContainer();
}
return self::$instance;
}
public function setContainer($container)
{
$this->container = $container;
}
/**
* #return mixed
*/
public function getContainer()
{
return $this->container;
}
}
so now its possible to create a "MainController" like this:
class Controller
{
/**
* #var mixed
*/
protected $view;
/**
* #var
*/
protected $router;
public function __construct()
{
$container = CurrentContainer::getInstance()->getContainer();
$this->view = $container->view;
$this->router = $container->router;
}
}
now all of my Controllers extends from the Controller class...
my question is now ... its that a good idea or is there a reason to not do it like that?
im thankful for every input
I've built some APIs with Slim Framework, and also tried so many method to get it done (of course in right way). I implemented MVC pattern on Slim Framework. The code example below:
For the controller, I created a base controller that injected with container. So the code:
<?php
namespace App\Controller;
use Slim\Container;
class Controller
{
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
public function __get($name)
{
return $this->container->get($name);
}
}
I loaded the base controller on dependencies container.
<?php
// controller
$container['controller'] = function ($c) {
return new App\Controller\Controller($c);
};
So I can get the container from the controller.
<?php
namespace App\Controller;
use App\Controller\Controller;
use Slim\Http\Request;
use Slim\Http\Response;
class HomeController extends Controller
{
public function __invoke(Request $request, Response $response, $args)
{
return $this->renderer->render($response, 'home');
}
}
I hope it helps.

Can I read input from GET inside a Controller Factory?

This question is not explicitly about ZF2, but I often take ques from ZF2 for my code. That said, most ZF2 examples I have seen process input inside a Controller Action.
Example:
class YourController extends AbstractActionController
{
public function doStuffAction()
{
// ZF2's way to get input from $_GET variable
$product = $this->getEvent()->getRouteMatch()->getParam('product');
// Process
$processor = (new ProcessorFactory())->getProcessor($product);
$output = $processor->processInput($data);
}
}
Now, I would like to inject a Processor into my Controller. Not create it inside the controller like I am doing above. But since Processor depends on knowing the $product, which is only gotten from $_GET, I do not see any other way.
If I want to inject Processor into Controller, I have to move the line that populates $product variable outside of the Controller as well.
How can I do so without breaking OOP, ZF2, design patterns badly? As in, I am under the impression that anything to do with $_GET is to be done inside a Controller, and not inside a ControllerFactory. Unless perhaps I can break this pattern?
If you just want to apply the Dependency Inversion principle. Applying the D of SOLID acronym, only a few changes are needed.
class YourController
{
/**
* #var ProcessorFactory
*/
protected $processorFactory;
public function __construct(ProcessorFactory $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function doStuffAction()
{
$product = $this->getEvent()->getRouteMatch()->getParam('product');
$processor = $this->processorFactory->getProcessor($product);
}
}
You could improve by typehinting to an Interface (SOLID)
class YourController
{
/**
* #var ProcessorFactoryInterface
*/
protected $processorFactory;
public function __construct(ProcessorFactoryInterface $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function doStuffAction()
{
$product = $this->getEvent()->getRouteMatch()->getParam('product');
$processor = $this->processorFactory->getProcessor($product);
}
}
Now, if you want don't want your Controller to be responsible of initiating the creating process (SOLID), you can split it up some more.
class YourController
{
/**
* #var ProcessorInterface
*/
protected $processor;
public function __construct(ProcessorInterface $processor)
{
$this->processor = $processor;
}
public function doStuffAction()
{
$processor = $this->processor;
}
}
class ControllerFactory
{
/**
* #var ProcessorFactory
*/
protected $processorFactory;
public function __construct(ProcessorFactory $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function create()
{
return new YourController($this->processorFactory->getProcessor());
}
}
class ProcessorFactory
{
/**
* #var RouteMatch
*/
protected $routeMatch;
public function __construct(RouteMatch $routeMatch)
{
$this->routeMatch = $routeMatch;
}
public function getProcessor()
{
$processor = $this->createProcessor();
// do stuff
return $processor;
}
protected function createProcessor()
{
$product = $this->routeMatch->getParam('product');
// create processor
return $processor;
}
}
The following code would get you your controller.
$controllerFactory = new ControllerFactory(new ProcessorFactory(new RouteMatch()));
$yourController = $controllerFactory->create();
Now above code is more general code and not adapted for ZF2. A good move would then to involve the ZF2's servicemanager.
class YourController extends AbstractActionController
{
/**
* #var ProcessorInterface
*/
protected $processor;
public function __construct(ProcessorInterface $processor)
{
$this->processor = $processor;
}
public function doStuffAction()
{
$processor = $this->processor;
}
}
class YourControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $controllers)
{
$services = $controllers->getServiceLocator();
$processorFactory = $services->get('ProcessorFactory');
return new YourController($processorFactory->getProcessor());
}
}
class ProcessorFactory
{
/**
* #var RouteMatch
*/
protected $routeMatch;
public function __construct(RouteMatch $routeMatch)
{
$this->routeMatch = $routeMatch;
}
public function getProcessor()
{
$processor = $this->createProcessor();
// do stuff
return $processor;
}
protected function createProcessor()
{
$product = $this->routeMatch->getParam('product');
// create processor
return $processor;
}
}
class ProcessorFactoryFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $services)
{
return new ProcessorFactory($services->get('RouteMatch'));
}
}
Above services/controllers and their factories should be registered with their ServiceManager/ControllerManager
$config = [
'controllers' = [
'factories' [
'YourController' => 'YourControllerFactory',
],
],
'service_manager' = [
'factories' [
'ProcessorFactory' => 'ProcessorFactoryFactory',
],
],
];
When a request gets dispatch to YourController, the ControllerManager returns a YourController instance with a Processor injected. Which Processor it gets depends on the request (a parameter inside RouteMatch).

Wrapping all methods of a controller in Recess

In recess, I have a controller
/**
* !RespondsWith Layouts
* !Prefix user/
*/
class UserController extends Controller
{
......
}
I want to wrap all methods of the UserController using Iwrapper. I know how to wrap method of a normal class using IWrapper. But in the case of the controller, i 'm not being able to do it because the UserController is not instantiated and its methods are called automatically by the recess controller.
You can use annotations to add a wrapper to the controller class. For instance, I have a controller "nas"
/**
* !RespondsWith Json,CSV
* !Prefix nas/
*/
class NasController extends Controller {
/**
* !Route GET
* !VerifyPermission Module: data, Permission: read, UnauthorizedAction: noEntry
*/
function index() {
}
}
The VerifyPermission annotation will add a wrapper in the expand method
Library::import('recess.lang.Annotation');
Library::import('cirrusWorks.wrappers.VerifyPermissionWrapper');
class VerifyPermissionAnnotation extends Annotation {
protected function expand($class, $reflection, $descriptor) {
$module = $this->module;
$permission = $this->permission;
$unauthorizedAction = $this->unauthorizedaction;
$descriptor->addWrapper('serve',new VerifyPermissionWrapper($module,$permission,$unauthorizedAction, $reflection->getName()));
/* ... */
return $descriptor;
}
}
Then you can create the VerifyPermissionWrapper and the standard methods will be wrapped around your class method (before(), after(), combine())
class VerifyPermissionWrapper implements IWrapper {
function __construct($module, $permission, $action, $method) {
$this->module = $module;
$this->permission = $permission;
$this->action = $action;
$this->method = $method;
}
function before($controller, &$args) {
error_log('Before {$this->action} on {$this->method}');
}
}

Categories