I am trying to implement View Strategy in ZF2.
As far as the basic setup, everything seem to be working fine except that ViewEvent Renderer is always null, thus the renderer never gets injected to the Strategy, and TemplateResolver still requests a template and displays the following error.
PhpRenderer::render: Unable to render template "api/api/get"; resolver could not resolve to a file'
I have even tried to copy the code JsonModel and JsonStrategy from ZF2, and still get the same result.
ViewYamlStrategy.php
public function selectRenderer(ViewEvent $e)
{
$renderer = $e->getRenderer(); // Always return null
}
module.php
public function getServiceConfig()
{
return ['factories' => [
'ViewYamlRenderer' => "Namespace\Mvc\Service\ViewYamlRendererFactory",
'ViewYamlStrategy' => "Namespace\Mvc\Service\ViewYamlStrategyFactory",
],
];
}
module.config.php
'view_manager' => [
'strategies' => [
'ViewYamlStrategy'
],
],
controller
public function getList()
{
return new YamlModel($data);
}
ViewYamlStrategy.php
function __construct(ViewYamlRenderer $renderer)
{
$this->renderer = $renderer;
}
public function attach(EventManagerInterface $events, $priority = 1)
{
$this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, [$this, "selectRenderer"], $priority);
$this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, [$this, "injectResponse"], $priority);
}
public function selectRenderer(ViewEvent $e)
{
$renderer = $e->getRenderer();
if ($this->renderer !== $renderer) {
return;
}
}
public function injectResponse(ViewEvent $e)
{
$renderer = $e->getRenderer(); // Always null
if ($this->renderer !== $renderer) {
return;
}
$result = $e->getResult();
$response = $e->getResponse();
$response->setContent($result);
}
ViewYamlRenderer.php
public function render($nameOrModel, $values = null)
{
return $nameOrModel->serialize();
}
public function setResolver(\Zend\View\Resolver\ResolverInterface $resolver)
{
$this->resolver = $resolver;
}
YamlModel.php
protected $captureTo = null;
protected $terminate = true;
public function serialize()
{
/*Serialize Object and return a string*/
}
thanks
I think this is due to the order that the strategies/listeners are triggered; As once a ViewRender is found the event propagation is halted and that renderer is returned.
It seems that the standard PhpRenderStrategy has a default event priority of 1 and the others (JsonStrategy etc) seem to fire prior to this (with an even priority of 100)
Try changing the $priority; perhaps 101
$this->listeners[] = $events->attach(
ViewEvent::EVENT_RENDERER,
[$this, "selectRenderer"],
101 // <-- change here
);
I have finally found the issue.
ViewYamlStrategy.php
/* This should return a renderer */
public function selectRenderer(ViewEvent $e)
{
// here I was checking the Renderer which was not created yet
// and instead I should've checked the model
$model = $e->getModel();
if (!$model instanceof YamlModel) {
return;
}
return $this->renderer;
}
Related
I am working on Album Application in zf3.I added acl functionality to the application like this:
AlbumController.php
class AlbumController extends AbstractActionController
{
protected $role;
public function onDispatch(\Zend\Mvc\MvcEvent $e)
{
$userSession = new Container('user');
if (!isset($userSession->email)) {
return $this->redirect()->toRoute('login');
}
else {
$this->role = $userSession->role;
parent::onDispatch($e);
}
}
public function checkPermission($role,$action)
{
if($role == 'admin'){
$acl = new Acl();
if ($acl->isAllowed('admin', 'AlbumController', $action)) {
return true;
}
}
return false;
}
public function editAction()
{
$action = 'edit';
$permission = $this->checkPermission($this->role,$action);
if (!$permission) {
$this->flashMessenger()->addMessage('<div class="alert alert- danger" role="alert"><b>You dont have the privilege to edit!!</b></div>');
return $this->redirect()->toRoute('album');
}
$id = (int) $this->params()->fromRoute('id', 0);
if (0 === $id) {
return $this->redirect()->toRoute('album', ['action' => 'add']);
}
try {
$album = $this->table->getAlbum($id);
} catch (\Exception $e) {
return $this->redirect()->toRoute('album', ['action' => 'index']);
}
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
$viewData = ['id' => $id, 'form' => $form];
if (! $request->isPost()) {
return $viewData;
}
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
$edit = $request->getPost('submit', 'Cancel');
if($edit == 'Cancel'){
$this->flashMessenger()->addMessage('<div class="alert alert-danger" role="alert"><b>Cancelled by User...!!</b></div>');
return $this->redirect()->toRoute('album');
}
if (! $form->isValid()) {
$this->flashMessenger()->addMessage('<div class="alert alert-danger" role="alert"><b>Failed to Update...!!</b></div>');
return $viewData;
}else{
$this->table->saveAlbum($album);
$this->flashMessenger()->addMessage('<div class="alert alert-success" role="alert"><b>Record Updated Successfully...!!</b></div>');
}
// Redirect to album list
return $this->redirect()->toRoute('album', ['action' => 'index']);
}
}
This is working perfectly fine,now i want to move the onDispatch function to Module.php but don't know how to implement it.Can someone please help me
Module.php
<?php
namespace Album;
use Album\Controller\AlbumController;
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Album\Model\LoginTable;
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function getServiceConfig()
{
return [
'factories' => [
AlbumTable::class => function($container) {
$tableGateway = $container->get(Model\AlbumTableGateway::class);
return new AlbumTable($tableGateway);
},
Model\AlbumTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
Model\LoginTable::class => function($container) {
$tableGateway = $container->get(Model\LoginTableGateway::class);
$table = new LoginTable($tableGateway);
return $table;
},
Model\LoginTableGateway::class => function ($container){
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
return new TableGateway('login', $dbAdapter, null, $resultSetPrototype);
}
],
];
}
public function getControllerConfig()
{
return [
'factories' => [
Controller\AlbumController::class => function($container) {
return new Controller\AlbumController($container->get(Model\AlbumTable::class));
},
Controller\LoginController::class => function($container) {
return new Controller\LoginController($container->get(Model\LoginTable::class));
},
Controller\LogoutController::class => function($container){
return new Controller\LogoutController($container->get(Model\LoginTable::class));
},
],
];
}
}
This is how I implemented it. In your Module.php, add a listener on EVENT_DISPATCH, with a closure as callback that will call your middleware class authorization :
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$eventManager = $app->getEventManager();
$serviceManager = $app->getServiceManager();
// Register closure on event DISPATCH, call your checkProtectedRoutes() method
$eventManager->attach(MvcEvent::EVENT_DISPATCH, function (MvcEvent $e) use ($serviceManager) {
$match = $e->getRouteMatch();
$auth = $serviceManager->get(Middleware\AuthorizationMiddleware::class);
$res = $auth->checkProtectedRoutes($match);
if ($res instanceof Response) {
return $res;
}
}, 1);
// Init ACL : could be improved
$this->initAcl($e);
}
You should have an AuthorizationMiddlewareFactory (call it as you want):
<?php
namespace MyModule\Factory;
use Interop\Container\ContainerInterface;
use MyModule\Middleware\AuthorizationMiddleware;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;
class AuthorizationMiddlewareFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$authService = $container->get(AuthenticationService::class);
$acl = $container->get('Acl'); // II init it in bootstrap(), could be improved
$response = $container->get('Response');
$baseUrl = $container->get('Request')->getBaseUrl();
$authorization = new AuthorizationMiddleware($authService, $acl, $response, $baseUrl);
return $authorization ;
}
}
And your AuthorizationMiddleware class:
<?php
namespace MyModule\Middleware;
use Symfony\Component\VarDumper\VarDumper;
use Zend\Authentication\AuthenticationService;
use Zend\Http\PhpEnvironment\Response;
use Zend\Permissions\Acl\Acl;
use Zend\Router\RouteMatch;
class AuthorizationMiddleware
{
private $authService ;
private $acl;
private $response;
private $baseUrl;
/**
* AuthorizationMiddleware constructor.
* #param AuthenticationService $authService
* #param Acl $acl
* #param Response $response
* #param $baseUrl
*/
public function __construct(AuthenticationService $authService, Acl $acl, Response $response, $baseUrl)
{
$this->authService = $authService;
$this->acl = $acl;
$this->response = $response;
$this->baseUrl = $baseUrl;
}
public function checkProtectedRoutes(RouteMatch $match)
{
if (! $match) {
// Nothing without a route
return null ;
}
// Do your checks...
}
It can be improved, but you have the idea... See also this Question and the answers: ZF3 redirection after ACL authorization failed
During saving I recive an error:
values() expects an array of values or Zend\Db\Sql\Select instance
I think error comes from:
$this->tableGateway->insert($procedure);
I don't understand what is wrong.
This is my process function:
public function processAction()
{
if (!$this->request->isPost()){
return $this->redirect()->toRoute(null, array('controller'=>'test', 'action'=>'index'));
}
$post = $this->request->getPost();
$form = new TestForm();
$inputFilter = new \Postepowania\Form\TestFilter();
$form->setInputFilter($inputFilter);
$form->setData($post);
if (!$form->isValid()){
$model = new ViewModel(
array(
'error' => true,
'form' =>$form,
)
);
$model->setTemplate('postepowania/test/index');
return $model;
}
$this->createTest($form->getData());
//return $this->redirect()->toRoute(null,array('controller' => 'test','action' => 'confirm',));
}
and createTest function:
public function createTest(array $data){
$testTable = $this->getServiceLocator()->get('TestTable');
$test = new Test();
$test->exchangeArray($data);
$testTable->save($test);
return true;
}
Save function is very simple:
public function save(Test $procedure)
{
$id = (int)$procedure->id;
if($id == 0)
{
$this->tableGateway->insert($procedure);
}
}
$this->tableGateway->insert()
From looking at the source, insert() requires an array to be passed into it, not an object. I suggest converting your object to an array before passing it in.
I want my form fields to contain the previous data contained in database when the form page opens. I went through lots of queries here and came to know using populate() or bind() method is the way to do it. But when I try to use it, I get an undefined method error.
Is there any other way to do it?
I am unable to use bind() as well. I am getting a fresh form with default values after I submit.
Sorry if this is a stupid question. Its been only 4-5 days since I started learning Zend framework. Also, most of the methods I get online are for older frameworks. I am using Zend Framework2.
This is Controller Code
<?php
class ChatController extends AbstractActionController
{
protected $chatTable;
public function indexAction()
{
$form = new ChatForm();
$model= new Chat();
$form->bind($model);
$form->get('submit')->setValue('Save');
$request = $this->getRequest();
if ($request->isPost()) {
$gen_set = new Chat();
$form->setInputFilter($gen_set->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$gen_set->exchangeArray($form->getData());
$this->getChatTable()->saveChat($gen_set);
// Redirect to list of albums
return $this->redirect()->toRoute('chat');
}
}
return array('form' => $form);
}
public function getChatTable()
{
if (!$this->chatTable) {
$sm = $this->getServiceLocator();
$this->chatTable = $sm->get('Chat\Model\ChatTable');
}
return $this->chatTable;
}
}
My Entity Class, Here api_key and anon_prefix are rows of the column 'settings' and there is one more column with value.
<?php
class Chat implements InputFilterAwareInterface
{
protected $inputFilter;
public function exchangeArray($data)
{
$this->api_key=(isset($data['api_key'])) ? $data['api_key'] : null;
$this->anon_prefix = (isset($data['anon_prefix'])) ? $data['anon_prefix'] : null;
}
// Add content to these methods:
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'iflychat_external_api_key',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
));
$inputFilter->add(array(
'name' => 'iflychat_show_admin_list',
'required' => true,
'validators' => array(
array(
'name' => 'InArray',
'options' => array(
'haystack' => array(1,2),
),
),
),
));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
This is used to enter values into db
<?php
class ChatTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function saveChat(Chat $gen_set)
{
$data = array(
'value' => $gen_set->api_key,
);
$id='iflychat_external_api_key';
$this->tableGateway->update($data,array('settings' => $id));
$data = array(
'value' => $gen_set->anon_prefix,
);
$id='anon_prefix';
$this->tableGateway->update($data,array('settings' => $id));
}
}
I am getting this error, 'Cannot use object of type Chat\Model\Chat as array'
Your action doesn't make much sense as it is, you instantiate a Chat instance as $model and later another instance as $gen_set. What you should be doing is binding the first one, and using the form class getData method to later return the instance you bound to it, along with the values you gave it in the setData method. There's no need for any transformations from object to array and back again.
Here's how it should look ...
public function indexAction()
{
$form = new ChatForm();
// bind the model
$model= new Chat();
$form->bind($model);
$form->get('submit')->setValue('Save');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($gen_set->getInputFilter());
// set data from POST as properties of the bound model ...
$form->setData($request->getPost());
if ($form->isValid()) {
// get the bound model instance with the POSTed values
// ($gen_set is now the original $model object instance bound above)
$gen_set = $form->getData();
// and save it
$this->getChatTable()->saveChat($gen_set);
// Redirect to list of albums
return $this->redirect()->toRoute('chat');
}
}
return array('form' => $form);
}
Controller Code -
<?php
class ChatController extends AbstractActionController {
protected $chatTable;
public function indexAction() {
$model = $this->getChatTable()->fetchLastChat();
if($model === null || $model->count() == 0)
$model = new Chat();
//Now if no record exists in the database then $model will be empty
//Else $model will contain data of last record.
$form = new ChatForm();
$form->bind($model);
$form->get('submit')->setValue('Save');
$request = $this->getRequest();
if ($request->isPost()) {
$gen_set = new Chat();
$form->setInputFilter($gen_set->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$gen_set->exchangeArray($form->getData());
$this->getChatTable()->saveChat($gen_set);
}
}
return array('form' => $form);
}
public function getChatTable() {
if (!$this->chatTable) {
$sm = $this->getServiceLocator();
$this->chatTable = $sm->get('Chat\Model\ChatTable');
}
return $this->chatTable;
}
}
ChatTable Class Code -
<?php
//Other use statements
use Zend\Db\Sql\Select;
class ChatTable {
protected $tableGateway;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}
public function fetchAll() {
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function fetchLastChat() {
$select = new Select('TABLE_NAME'); //Change the tablename accordingly
$select->order('PRIMARY_KEY DESC'); //Set the Primary Key of the table
$select->limit(1);
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet->current();
}
//Rest of the Code ....
Please take the idea from the above code.
I am trying to implement Custom authentication via SOAP webservice
as per Refering links
http://it-cook-de.blogspot.in/2013/07/zend-framework-2-custom-authentication-with-soap-webservice-part-1.html
http://samsonasik.wordpress.com/2012/10/23/zend-framework-2-create-login-authentication-using-authenticationservice-with-rememberme/#comment-6117
Now getting error as
Code :
<?php
namespace Application\Adapter;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Authentication\Result;
use Zend\Soap\Client;
use Zend\Soap\Client\DotNet as DotNet;
class SoapAuthenticationAdapter implements AdapterInterface
{
//:TODO: move to configuration
//private $module = 'my_application_name_in_auth_system';
private $module = 'student';
//:TODO: move to configuration
// private $uri = 'full_url_to_soap_webservice_of_auth_system';
private $uri = 'http://ip/Service/student.svc?wsdl';
//:TODO: move to configuration
//private $location = 'full_url_to_soap_webservice_of_auth_system';
private $location = 'http://ip/Service/student.svc?wsdl';
protected $username;
protected $password;
protected $customercode;
function __construct()
{
}
public function authenticate()
{
$client = new DotNet($this->uri);
$param=array("customercode"=>$this->customercode,"username"=>$this->username,"password"=>$this->password);
$result = $client->call('ValidateUser',array($param));
if ($result) {
$this->permissions = $param;
return $this->getResult(Result::SUCCESS, $this->permissions, 'SUCCESS');
} else {
return $this->getResult(Result::FAILURE_CREDENTIAL_INVALID, null, 'FAILURE_CREDENTIAL_INVALID');
}
} catch (\SoapFault $e) {
// switch ($e->getMessage()) {
return $this->getResult(Result::FAILURE_UNCATEGORIZED, null, $e->getMessage());
// }
}
}
public function setIdentity($username)
{
$this->username = $username;
}
public function setCredential($password)
{
$this->password = $password;
}
public function setCustomerCode($customercode)
{
$this->customercode =$customercode;
}
private function getResult($type, $identity, $message)
{
return new Result($type, $identity, array(
$message
));
}
}
/////In IndexController
public function getAuthService()
{
if (! $this->authservice) {
$this->authservice = $this->getServiceLocator()
->get('SoapAuthenticationService');
}
return $this->authservice;
}
public function someAction()
{
$request = $this->getRequest();
if ($request->isPost()){
$this->getAuthService()->getAdapter()
->setIdentity($request->getPost('username'))
->setCredential($request->getPost('password'))
->setCustomerCode($request->getPost('customercode'));
$result = $this->getAuthService()->authenticate();
foreach($result->getMessages() as $message)
{
//save message temporary into flashmessenger
$this->flashmessenger()->addMessage($message);
}
if ($result->isValid()) {
$redirect = 'home';
//check if it has rememberMe :
if ($request->getPost('rememberme') == 1 ) {
$this->getSessionStorage()
->setRememberMe(1);
//set storage again
$this->getAuthService()->setStorage($this->getSessionStorage());
}
$this->getAuthService()->setStorage($this->getSessionStorage());
$this->getAuthService()->getStorage()->write($request->getPost('username'));
}
else
{
$redirect ='login';
}
return $this->redirect()->toRoute($redirect);
}
in module.php
public function getServiceConfig()
{
return array(
'factories' => array(
//Add the following lines
'Application\Model\SoapAuthenticationStorage' => function($sm){
return new SoapAuthenticationStorage('student');
},
'SoapAuthenticationService' => function($sm) {
$authAdapter = new SoapAuthenticationAdapter();
$authService = new AuthenticationService();
$authService->setAdapter($authAdapter);
$authService->setStorage($sm->get('Application\Model\SoapAuthenticationStorage'));
return $authService;
}
)
);
}
Any help to solve this
Each of the set methods in your adapter need to return $this in order to allow you to chain method calls together (this is called a 'fluent interface'). E.g.:
public function setIdentity($username)
{
$this->username = $username;
return $this;
}
That should fix the error you're getting.
I am coding a custom validation to my .NET MVC 4 application. This is the first validation that uses a parameter, and I'm finding some trouble to get this.
This is my C# code:
ValidationAttribute:
namespace Validations
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MinRequiredPasswordLengthValidationAttribute : ValidationAttribute, IClientValidatable
{
public MinRequiredPasswordLengthValidationAttribute()
: base("The password is invalid")
{
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name.ToLower(), Membership.MinRequiredPasswordLength);
}
public override bool IsValid(object value)
{
if (value == null || String.IsNullOrEmpty(value.ToString()))
{
return true;
}
return value.ToString().Length >= Membership.MinRequiredPasswordLength;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientMinRequiredPasswordLengthValidationRule rule = new ModelClientMinRequiredPasswordLengthValidationRule(FormatErrorMessage(metadata.GetDisplayName()), Membership.MinRequiredPasswordLength);
yield return rule;
}
}
}
ModelClientValidationRule:
namespace Validations
{
public class ModelClientMinRequiredPasswordLengthValidationRule : ModelClientValidationRule
{
public ModelClientMinRequiredPasswordLengthValidationRule(string errorMessage, int minRequiredPasswordLength)
{
ErrorMessage = errorMessage;
ValidationType = "minrequiredpasswordlength";
ValidationParameters.Add("minlength", minRequiredPasswordLength);
}
}
}
And here is the JS code, my problem:
jQuery.validator.addMethod("minrequiredpasswordlength", function (value, element, params) {
if (value.length == 0) {
return true; //empty
}
return true; //dummy return
}, "");
jQuery.validator.unobtrusive.adapters.add("minrequiredpasswordlength", {}, function (options) {
//XXX Here I should get the minlength parameter, but 'options' is a empty object
options.messages["minrequiredpasswordlength"] = options.message;
});
Many thanks for the help!
see if this link helps:
ASP.NET MVC 3 client-side validation with parameters
Also, try changing your javascript code to this:
$.validator.addMethod('minrequiredpasswordlength', function (value, element, params) {
var minLength = params.minLength;
// minLength should contain your value.
return true; // dummy return
});
jQuery.validator.unobtrusive.adapters.add('minrequiredpasswordlength', [ 'minlength' ], function (options) {
options.rules['minrequiredpasswordlength'] = {
minLength: options.params['minlength']
};
//XXX Here I should get the minlength parameter, but 'options' is a empty object
options.messages["minrequiredpasswordlength"] = options.message;
});
The secret here is to use [ 'minlength' ] instead of {} It took me a lot of time when I first learnt this. I hope this helps.