Symfony Request: setController, setAction, setModule - php

In zf2 I have the option to make fake requests with a Zend/Request object. Thus I can do an internal Request. I want to execute a part of my site with a few data. Thus, I must use a Controller, Module and a Action.
How would I do that?
Here's a snippet of code from zf2 from a previous question:
/application/controller/IndexController.php
<?php
class IndexController extends Zend_Controller_Action
{
public function init(){}
public function indexAction()
{
//process some data from $_GET, $_POST, maybe (via framework, ofc).
}
}
/public/index2.php
<?php
//--cut--
$application->bootstrap();
$options = array(
'action' => 'index',
'controller' => 'index',
'module' => 'default'
);
if( isset($options['action'], $options['module'], $options['controller']) )
{
//*
$request = new Zend_Controller_Request_Http ();
$request->setModuleName($options['module'])->setActionName($options['action'])->setControllerName($options['controller']);
$frontController = Zend_Controller_Front::getInstance ()->returnResponse ( true );
//*/
$response = new Zend_Controller_Response_Http ();
$frontController->getDispatcher ()->dispatch ( $request, $response );
var_dump($response);
}
Thank you!

Related

Wordpress - Testing custom API endpoint with class dependency

Sorry I feel like really stuck here.
I have a plugin introducing a new Rest API controller (WP_REST_Controller) with basically a single endpoint which uses a separate class as a client to fetch some data. Let's say:
#my_plugin.php
function register_items_routes() {
if ( ! class_exists( 'WP_REST_My_Controller' ) ) {
require_once __DIR__ . '/class-wp-my-controller.php';
}
$controller = new WP_REST_My_Controller();
$controller->register_routes();
}
add_action( 'rest_api_init', 'register_items_routes' );
_
#class-wp-my-controller.php
class WP_REST_My_Controller extends WP_REST_Controller {
/**
* Registers the routes.
*/
public function register_routes() {
$namespace = 'my/namespace';
$path = 'get-items';
register_rest_route( $namespace, '/' . $path, [
array(
'methods' => 'GET',
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' )
),
] );
}
public function get_items_permissions_check( $request ) {
return true;
}
/**
* Get items from My_Class and return them.
*
* #param WP_REST_Request $request The incoming HTTP request.
*
* #return WP_REST_Response|WP_Error The response containing the items in JSON, WP_Error in case of error.
*/
public function get_items( $request ) {
$client = new My_Class();
try {
$items = $client->fetch_some_items();
} catch ( Exception $e ) {
return new WP_Error(
'some-client-error',
$e->getMessage()
);
// Code to be tested. - Do some stuff with items and return.
return new WP_REST_Response( $items );
}
How am I supposed to stub the My_Class dependency from PhpUnit in order to return a predefined set of items which I could test with?
public function test_get_items() {
$request = new WP_REST_Request( 'GET', '/my/namespace/get-items' );
$data = rest_get_server()->dispatch( $request );
$expected_items = [
'some_key1' => 'some_value1',
'some_key2' => 'some_value2',
];
$this->assertTrue( count($data['items']) == count($expected_items) );
}

Can not access method in CakePHP

I am working in CakePHP 2.6.1 and I have a project in which I have to create an API. So I have created a function and its working fine when I am logged in but when I try to access without login, it redirects to the login page.
My function looks like :
class AndroidController extends AppController {
public function admin_survey_question()
{
$this->loadModel('Question');
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$this->Question->unbindModel(
array('hasMany' => array('Result'))
);
$info = $this->Question->find('all', array(
'fields' => array('Question.id,Question.question, Question.options'),
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
Here,In core.php there is a Routing.prefixes used as admin.
Configure::write('Routing.prefixes', array('admin','services'));
When I call this api
http://navyon.com/dev/mt/admin/android/survey_question?survey_id=2
then it redirects to the login page.
I need access api without login.So how can I resolve this problem?
To make accessible this method admin_survey_question without authentication, you need to allow it in beforeFilter
class AndroidController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('admin_survey_question');
}
public function admin_survey_question()
{
$this->loadModel('Question');
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$this->Question->unbindModel(
array('hasMany' => array('Result'))
);
$info = $this->Question->find('all', array(
'fields' => array('Question.id,Question.question, Question.options'),
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
See Docs

Can not retrieve multiple records from the database in CakePHP

I am working with 2.6.1 version of CakePHP. I have created one controller named as AndroidController.php and that looks like
<?php
class AndroidController extends AppController {
public function survey_question()
{
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$info = $this->Question->find('all', array(
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
?>
So, it gives an error like
Error: The action admin_survey_question is not defined in controller
AndroidController
Error:Create AndroidController::admin_survey_question() in file: app/Controller/AndroidController.php.
Note :My website url is
http://navyon.com/dev/mt/admin/android/survey_question?survey_id=2
So how can I resolve this?
You have enable admin routing for that action so your action should preceded admin_
Then your action look like below:
<?php
class AndroidController extends AppController {
public function admin_survey_question()
{
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$info = $this->Question->find('all', array(
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
?>
If you don't want enable admin routing for that action then remove admin from url and access like this :
http://navyon.com/dev/mt/android/survey_question?survey_id=2

zf2 How to get user details with AuthenticationService

I've created a module to authenticate a user. Now, after login I go to the index action and the system tells me that the authentication is all working fine. But What I want is to print some more user details from the Users table. When I try:
print_r($this->getServiceLocator()->get('AuthService')->getAdapter()->getResultRowObject());
I get no result. What am I doing wrong?
Thanks for your help.
In my module.php I've the following code(snippet):
public function getServiceConfig()
{
return array(
'abstract_factories' => array(),
'aliases' => array(),
'factories' => array(
// Some more code here but removed for simplicity
// Autentication
'AuthService' => function ($sm) {
$adapter = $sm->get('master_db');
$dbAuthAdapter = new DbAuthAdapter ( $adapter, 'Users', 'email', 'password' );
$auth = new AuthenticationService();
$auth->setAdapter ( $dbAuthAdapter );
return $auth;
},
// Some more code here but removed for simplicity
}
In my IndexController.php I've the following (snippets):
public function indexAction()
{
if(!$this->getServiceLocator()->get('AuthService')->hasIdentity()){
return $this->redirect()->toUrl('login');
}
echo "hello, it works!";
exit;
}
public function loginAction(){
$form = $this->getServiceLocator()->get('LoginForm');
$viewModel = new ViewModel(array('form' =>
$form));
return $viewModel;
}
public function processAction(){
// Lots of code here
if($bcrypt->verify($loginData['password'], $userData->password))
{
$this->getAuthService()
->getAdapter()
->setIdentity($loginData['email'])
->setCredential($userData->password);
$result = $this->getAuthService()->authenticate();
}
// Lots of code here where I check if $result->isValid and route to the
// correct action
}
public function getAuthService() {
if(!isset($this->authservice)) {
$this->authservice = $this->getServiceLocator()->get('AuthService');
}
return $this->authservice;
}
Instead of refering to the authentication result object (which properly only exists in the authentication request) you can simply store user details in the authentication identity (#see http://framework.zend.com/manual/2.1/en/modules/zend.authentication.intro.html).
For your case you could also store user specific details right after the validation of the authentication result in the authentication storage:
if ($result->isValid()) {
//authentication success
$resultRow = $this->authService->getAdapter()->getResultRowObject();
$this->authService->getStorage()->write(array(
'id' => $resultRow->id,
'user_agent' => $request->getServer('HTTP_USER_AGENT'))
);
}
(This information was taken from this authentication tutorial http://samsonasik.wordpress.com/2013/05/29/zend-framework-2-working-with-authenticationservice-and-db-session-save-handler/)

Zend 2: How to configure errors with custom controller?

My question is regarding customizing how errors are handled in Zend 2.
Suppose I'd like to customize the layout such that I want to do this in an action in my controller:
$layout = $this->layout();
$myNav = new ViewModel(array('nav' => $this->getNav());
$myNav->setTemplate('layout/nav');
$layout->addChild($myNav, 'navigation');
Works great when I place this into my controller for regular (i.e. non-404) viewing. Now I've customized my layout so that I can do <?php echo $this->navigation; ?> and the layout/nav.phtml is fired up and everything works just hunky dory.
Now, suppose I want to do the exact same thing when errors are rendered. I need to be able to inject the above code somehow prior to the error handler returning it's own ViewModel(...) into the error/404.phtml template.
How do you do that?
I suspect that it's something like setting up the correct class for the service manager like this in module.config.php:
'service_manager' => array(
'services' => array(
'error_handler' => 'MyModule\Controller\MyCustomErrorController'
//and so on...
How do I do this?
UPDATE:
In my Module.php I've attached a method for MvcEvent::EVENT_DISPATCH_ERROR. Variant A works, Variant B does not. So you can't use partials here?? Am I missing something really basic??
Variant A
public function onDispatchError(MvcEvent $event)
{
$sm = $event->getApplication()->getServiceManager();
$vm = $event->getViewModel();
$vm->setVariable('nav', '<h1>test do i work?</h1>');
//Works
}
Variant B
public function onDispatchError(MvcEvent $event)
{
$sm = $event->getApplication()->getServiceManager();
$vm = $event->getViewModel();
$nav = new ViewModel(array('test'=>'hello there'));
$nav->setTemplate('layout/simpletest');//contents: <?php echo $this->test; ?>
$vm->addChild($nav, 'nav');
//In the template, <?php echo $this->nav; ?> has nothing...
}
Zf2 use module.config.php file to set error handling:
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
This should handle 4xx client errors and 5xx server errors.
For custom error page in specific module.
namespace ModuleName;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\Mvc\MvcEvent;
class Module implements
BootstrapListenerInterface,
AutoloaderProviderInterface,
ConfigProviderInterface
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach('dispatch', array($this, 'loadConfiguration' ), 100);
}
public function loadConfiguration(MvcEvent $e)
{
$sm = $e->getApplication()->getServiceManager();
$controller = $e->getRouteMatch()->getParam('controller');
if (0 !== strpos($controller, __NAMESPACE__, 0)) {
//if not this module
return;
}
//if this module
$exceptionstrategy = $sm->get('ViewManager')->getExceptionStrategy();
$exceptionstrategy->setExceptionTemplate('error/errorcustom');
}
public function getAutoloaderConfig(){ /* common code */ }
public function getConfig(){ /* common code */}
}
The solution is provided by "samsonasik" from http://samsonasik.wordpress.com/2012/09/19/zend-framework-2-create-custom-error-page/
You can attach to an even to handle what happend when a 404 is triggered:
Module.php
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
/**
* Log any Uncaught Errors
*/
$sharedManager = $e->getApplication()->getEventManager()->getSharedManager();
$sm = $e->getApplication()->getServiceManager();
$sharedManager->attach('Zend\Mvc\Application', 'dispatch.error',
function($e) use ($sm) {
/**
* Decide what to do now we've got a problem...
* Log the issue etc..
* You could forward to some custom controller if you wanted..
*/
//$sm->get('Zend\Log\Logger')->crit('an error occurred... bla');
$controller = $e->getTarget();
//$routeMatch = $e->getRouteMatch();
$controller->layout('somelayout'); // possibly change the layout..
}
);
}

Categories