Zend/Session with ZfcUser - zend-framework2

I'm using ZfcUser in my app and I need to control the timeout parameter. As it's not part of the configuration I would like to set my own Zend/Session object (with the remember_me_seconds param) to ZfcUser on bootstrap but I don't know how.
By chance, has anyone done this already?

The easiest way to set session params is as follows
config\autoload\global.php
return array(
'service_manager' => [
'factories' => [
// Configures the default SessionManager instance
'Zend\Session\ManagerInterface' => 'Zend\Session\Service\SessionManagerFactory',
// Provides session configuration to SessionManagerFactory
'Zend\Session\Config\ConfigInterface' => 'Zend\Session\Service\SessionConfigFactory',
],
],
'session_manager' => [
// SessionManager config: validators, etc
],
'session_config' => [
'cache_expire' => 86400,
'cookie_lifetime' => 86400,
'remember_me_seconds' => 86400,
'gc_probability' => 10,
'gc_divisor' => 1000,
'use_cookies' => true,
'cookie_httponly' => true,
'cookie_lifetime' => 0, // to reset lifetime to maximum at every click
'gc_maxlifetime' => 86400,
],
);
And add line to onBootstrap method at Module.php
public function onBootstrap(MvcEvent $e)
{
$manager = $e->getApplication()->getServiceManager()->get('Zend\Session\ManagerInterface');
}
This will affect session setting and phpinfo() shows it.
I found it in zfcuser github

I don't use zfcuser but try this
autoload/global.php
<?php
use Zend\Session\Config\SessionConfig;
use Zend\Session\SessionManager;
use Zend\Session\Container;
return array(
'service_manager' => array(
'factories' => array(
'SessionManager' => function($sm) {
$sessionConfig = new SessionConfig();
$sessionConfig->setOption('remember_me_seconds', 1440);
$sessionManager = new SessionManager($sessionConfig);
Container::setDefaultManager($sessionManager);
return $sessionManager;
},
),
),
);
Module.php
public function onBootstrap($event)
{
$serviceManager = $event->getApplication()->getServiceManager();
$serviceManager->get('SessionManager')->start();
}

Here is how I did it. I am not the worlds greatest coder but this seems to work. This is all in Module.php
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$sharedManager = $eventManager->getSharedManager();
$sm = $e->getApplication()->getServiceManager();
//This checks to see if the user is logged in.
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'checkLogin'), 100);
}
//This function is attached to a listener to see if the user is not currently logged in
//If they are not logged in they will be redirected to the login page. This check will happen through the
//application so there is no need to keep checking in other modules
public function checkLogin (MvcEvent $e)
{
$session = new Container('defaults');
$this->route = $e->getRouteMatch();
$this->matchedRouteName = explode('/', $this->route->getMatchedRouteName());
$this->route_root = $this->matchedRouteName[0];
$sm = $e->getApplication()->getServiceManager();
$zfcServiceEvents = $sm->get('ZfcUser\Authentication\Adapter\AdapterChain')->getEventManager();
$zfcServiceEvents->attach(
'authenticate',
function ($e) use ($session) {
$session->offsetSet('sessionstart', $_SERVER['REQUEST_TIME']);
}
);
$auth = $sm->get('zfcuser_auth_service');
if (!$auth->hasIdentity() && $this->route_root != 'zfcuser')
{
$response = new \Zend\Http\PhpEnvironment\Response();
$response->getHeaders()->addHeaderLine('Location', '/user/login');
$response->setStatusCode(302);
$response->sendHeaders();
$e->stopPropagation(true);
return $response;
}
else if ($auth->hasIdentity() && $session->offsetGet('sessionstart') < ($_SERVER['REQUEST_TIME'] - 10800) && $this->route_root != 'zfcuser')
{
$response = new \Zend\Http\PhpEnvironment\Response();
$response->getHeaders()->addHeaderLine('Location', '/user/logout');
$response->setStatusCode(302);
$response->sendHeaders();
$e->stopPropagation(true);
return $response;
}
else if ($auth->hasIdentity())
{
$session->offsetSet('sessionstart', $_SERVER['REQUEST_TIME']);
}
}

Related

Show username of logged in user in zf2

I have login and logout system in ZF2. I want to show username of logged in user when he/she is logged in. Screen shot is given below:
I have different views like view/provinces/index.phtml, view/districts/index.phtml, etc.
I have layout.phtml in view/layout/layout.phtml, in which I described layout for admin which is for every view. So It is necessary to access username of logged in user in layout.phtml.
I have also corresponding controllers like Controller/ProvincesController.php, Controller/DistrictsController.php etc. I can access username of logged in user in Controller/ProvincesController.php etc by the code:
public function getAuthService()
{
$this->authservice = $this->getServiceLocator()->get('AuthService');
return $this->authservice;
}
$username = $this->getAuthService()->getStorage()->read();
But I am unable to access value of username of logged in user in layout.phtml.
So if anyone know about it or have simple idea or practice about it, then let me know please.
Module.php:
<?php
namespace Admin;
use Admin\Model\Profile;
use Admin\Model\ProfileTable;
use Admin\Model\Provinces;
use Admin\Model\ProvincesTable;
use Admin\Model\Districts;
use Admin\Model\DistrictsTable;
use Admin\Model\User;
use Admin\Model\UserTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\Authentication\Adapter\DbTable as DbTableAuthAdapter;
use Zend\Authentication\AuthenticationService;
class Module implements AutoloaderProviderInterface
//class Module
{
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig()
{
return array(
'abstract_factories' => array(),
'aliases' => array(),
'factories' => array(
// SERVICES
'AuthService' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$dbTableAuthAdapter = new DbTableAuthAdapter($dbAdapter, 'user','username','password', 'MD5(?)');
$authService = new AuthenticationService();
$authService->setAdapter($dbTableAuthAdapter);
return $authService;
},
// DB
'UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null,
$resultSetPrototype);
},
// FORMS
'LoginForm' => function ($sm) {
$form = new \Admin\Form\LoginForm();
$form->setInputFilter($sm->get('LoginFilter'));
return $form;
},
// FILTERS
'LoginFilter' => function ($sm) {
return new \Admin\Form\LoginFilter();
},
'Admin\Model\ProvincesTable' => function($sm) {
$tableGateway = $sm->get('ProvincesTableGateway');
$table = new ProvincesTable($tableGateway);
return $table;
},
'ProvincesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Provinces());
return new TableGateway('provinces', $dbAdapter, null, $resultSetPrototype);
},
'Admin\Model\DistrictsTable' => function($sm) {
$tableGateway = $sm->get('DistrictsTableGateway');
$table = new DistrictsTable($tableGateway);
return $table;
},
'DistrictsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Districts());
return new TableGateway('districts', $dbAdapter, null, $resultSetPrototype);
},
),
'invokables' => array(),
'services' => array(),
'shared' => array(),
);
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
// if we're in a namespace deeper than one level we need to fix the \ in the path
__NAMESPACE__ => __DIR__ . '/src/' . str_replace('\\', '/' , __NAMESPACE__),
),
),
);
}
}
Thanks in advance.
The recommend way would be to use identity (https://framework.zend.com/manual/2.4/en/modules/zend.view.helpers.identity.html) view helper. Then in any view model you could use it as follow:
if ($user = $this->identity()) {
echo 'Logged in as ' . $this->escapeHtml($user->getUsername());
} else {
echo 'Not logged in';
}
In order to make it work you have to register your authentication service under specific name- Zend\Authentication\AuthenticationService.
So in your module.config.php file, add to service_manager:
'service_manager' => array(
'aliases' => array(
'Zend\Authentication\AuthenticationService' => 'AuthService', // <--- this line
),
'invokables' => array(
'AuthService' => 'Your\Authentication\Class',
),
),
Then you should be able to use identity controller plugin and view helper.
In your case, Module.php should look like this:
...
public function getServiceConfig()
{
return array(
'abstract_factories' => array(),
'aliases' => array(
'Zend\Authentication\AuthenticationService' => 'AuthService', // <--- this line
),
'factories' => array(
// SERVICES
'AuthService' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$dbTableAuthAdapter = new DbTableAuthAdapter($dbAdapter, 'user','username','password', 'MD5(?)');
$authService = new AuthenticationService();
$authService->setAdapter($dbTableAuthAdapter);
return $authService;
},
// DB
'UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null,
$resultSetPrototype);
},
// FORMS
'LoginForm' => function ($sm) {
$form = new \Admin\Form\LoginForm();
$form->setInputFilter($sm->get('LoginFilter'));
return $form;
},
// FILTERS
'LoginFilter' => function ($sm) {
return new \Admin\Form\LoginFilter();
},
'Admin\Model\ProvincesTable' => function($sm) {
$tableGateway = $sm->get('ProvincesTableGateway');
$table = new ProvincesTable($tableGateway);
return $table;
},
'ProvincesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Provinces());
return new TableGateway('provinces', $dbAdapter, null, $resultSetPrototype);
},
'Admin\Model\DistrictsTable' => function($sm) {
$tableGateway = $sm->get('DistrictsTableGateway');
$table = new DistrictsTable($tableGateway);
return $table;
},
'DistrictsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Districts());
return new TableGateway('districts', $dbAdapter, null, $resultSetPrototype);
},
),
'invokables' => array(),
'services' => array(),
'shared' => array(),
);
}
...
Then in your layout or any other .phtml file:
layout.phtml
...
<?php if ($this->identity()): ?>
<p>Welcome, <?php echo $this->identity()->getUsername(); ?></p>
<?php endif; ?>
Taking help of Mr. SzymonM's answer, I changed my Module.php as suggested by him, and write the following simple code in layout.phtml
This solve my issue and username is shown with first letter in Upper case.
<?php
if ($this->identity())
{
echo ucfirst($this->identity());
}
?>
//ucfirst is php function which make first letter Uppercase.

How to prevent after facebook login redirect url in popup?

This is my controller.
public function actions()
{
return [
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'oAuthSuccess'],
],
];
}
public function oAuthSuccess($client) {
$name = explode(" ",$userAttributes['name']);
$existing_customer = Customer::find()
->where(['email' => $userAttributes['email']])
->orWhere(['id_facebook' => $userAttributes['id']])
->one();
if(empty($existing_customer)){
$customer = new Customer();
$customer->firstname = $name[0];
$customer->lastname = $name[1];
$customer->id_default_group = 3;
$customer->username = $userAttributes['id'].'#facebook.com';
$customer->id_facebook = $userAttributes['id'];
$customer->email = $userAttributes['email'];
$password = rand(0000, 9999);
$auth_key = Yii::$app->getSecurity()->generateRandomString();
$customer->auth_key = $auth_key;
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
$customer->password_hash = $hash;
$customer->activation_code = $password;
$customer->active =1;
if ($customer->save(false)) {
$customergroup = new CustomerGroup();
$customergroup->id_customer = $customer->id_customer;
$customergroup->id_group = $customer->id_default_group;
$customergroup->save(false);
Yii::$app->response->redirect(['advanced','email' => $customer->email]);
}
}
This is my main.php file.
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'authUrl' => 'https://www.facebook.com/dialog/oauth?display=popup',
'clientId' => '',
'clientSecret' => '',
'scope' => [
'email',
'user_birthday',
'user_location',
'user_hometown',
],
],
],
],
Actually I am doing registration in 2 process.
After user click on facebook button it returns to my second step in popup, But i need it in my site. How is it possible?
change your auth successCallBack in action function with the action you desire..
below a sample where successCallback check if the user is a guest if true call the action authenticate otherwise the action connect
/** #inheritdoc */
public function actions()
{
return [
'auth' => [
'class' => AuthAction::className(),
'successCallback' => \Yii::$app->user->isGuest
? [$this, 'authenticate']
: [$this, 'connect'],
]
];
}
After the facebook login you return in your code inside the oAuthSuccess function .. i think the popup you are looking for is inside this function and is called from this redirect. if you want somethings others change the bootom part of this function..
Yii::$app->response->redirect(['advanced','email' => $customer->email]);

ZF2 - ApiGility installed in my own app - route not working

I am attempting to install APIGILITY in my app. I have followed this tutorial:
https://apigility.org/documentation/recipes/apigility-in-an-existing-zf2-application
When I attempt to access the apigility admin: www.myapp.dev/apigility I get a "The requested URL could not be matched by routing" error.
My config is as follows:
'modules' => array(
'DoctrineModule',
'DoctrineORMModule',
'ZfcRbac', //Keep this at the top
'Application', //The applications main functions run from this module
//APIGILITY
'ZF\Apigility',
'ZF\Apigility\Provider',
'AssetManager',
'ZF\ApiProblem',
'ZF\MvcAuth',
'ZF\OAuth2',
'ZF\Hal',
'ZF\ContentNegotiation',
'ZF\ContentValidation',
'ZF\Rest',
'ZF\Rpc',
'ZF\Versioning',
'ZF\DevelopmentMode',
'ZF\Apigility\Admin',
'ZF\Configuration',
I have enabled developer mode.
Typically if a route exists and ZfcRbac is blocking the route, I am re-directed. In this case when the route is not accessible I get the error.
Is there a simple way to test this?
To follow up on HappyCoder's own answer, you can match all routes in zf-apigility module with
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$e->getApplication()->getEventManager()->attach(
MvcEvent::EVENT_ROUTE, function(MvcEvent $e) {
// Route matched
$route_name = $e->getRouteMatch()->getMatchedRouteName();
// If apigility - set correct layout
if(preg_match('/^zf-apigility/', $route_name)) {
$e->getViewModel()->setTemplate('layout/api-layout');
}
}
);
}
When doing this way - it will set appropriate layout for all apigility views, including /apiligity (welcome screen)
I solved this issue by doing the following:
The tutorial makes no mention of copying the ApiGility template to your app. You need to do this. What I did was to add the template to my application/config/module.config.php file.
return [
'view_manager' => [
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/exception',
'template_map' => [
'customer/layout' => __DIR__ . '/../view/layout/customer-layout.phtml',
'api/layout' => __DIR__ . '/../view/layout/api-layout.phtml',
'layout/layout' => __DIR__ . '/../view/layout/admin-layout.phtml',
In the Application module I check routing and switch the template accordingly:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$e->getApplication()->getEventManager()->attach(
MvcEvent::EVENT_ROUTE, function(MvcEvent $e) {
//Set the customer layout
$needle = $e->getRouteMatch()->getParam('controller');
$haystack = [
/* Customer template routes */
];
if (in_array( $needle , $haystack )) {
$e->getViewModel()->setTemplate('customer/layout');
}
//Apigility route
$haystack = [
'zf-apigility/ui'
];
if (in_array( $needle , $haystack )) {
$e->getViewModel()->setTemplate('api/layout');
}
}
);
}
To access the apigility pages, I now access via: http://www.myapp.com/apigility/ui#/
Hope this helps someone...

event that adds a parameter to routing

Is it possible to hook up (ideally in the controller) to add an additional parameter to routing?
I know that sounds unclear and at first glance it may sounds ridiculous - because to reach the controller we already must have routing. But I want to change only default variables.
I'll try to explain what I want to achieve:
Config:
return [
'router' => [
'routes' => [
'some' => [
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => [
'route' => '/some/:project',
'defaults' => [
'__NAMESPACE__' => 'Some\Controller',
'controller' => 'Some\Controller\Some',
'action' => 'some',
'extra' => 'default-value'
],
],
]
]
]
];
Controller:
class SomeController extends AbstractActionController {
protected $project = null;
public function setEventManager(EventManagerInterface $events)
{
parent::setEventManager($events);
$controller = $this;
$events->attach(
'dispatch', function (\Zend\Mvc\MvcEvent $e) use ($controller) {
$params = $e->getRouteMatch()->getParams();
$this->project = $params['project'] ;
// and there should be something that I want to
// achieve but do not know how (and if it is possible)
if ($this->project == 1) {
// magic action which modify config default param
// "extra" from "default-value" to "changed-value"
}
return;
}, 50
);
}
protected function attachDefaultListeners()
{
parent::attachDefaultListeners();
$eventManager = $this->getEventManager();
$eventManager->attach(
\Zend\Mvc\MvcEvent::EVENT_DISPATCH,
function(\Zend\Mvc\MvcEvent $event) {
$ViewModel = $event->getResult();
if ($ViewModel instanceof \Zend\View\Model\ViewModel) {
$ViewModel->setVariable('project',$this->project);
}
},
-99);
}
public function someAction() {
echo $this->params()->fromRoute("extra"); // return "default-value";
// but i want
echo $this->params()->fromRoute("extra"); // return "changed-value";
return new ViewModel();
}
}
View
<?php
echo "project: ".$this->project;
echo $this->url('some',['project'=>1]); // result: "/some/1"
I know this seems very strange. But for some reason (readable links, seo) is necessary to me.
Are you sure, you want to change the default param?
if ($this->project == 1) {
$e->getRouteMatch()->setParam('extra', 'changed-value');
}
You can set default params globally for assembling:
$serviceLocator->get('router')->setDefaultParam('extra', 'changed-value');
There is no way to change the defaults-Property of Zend\Mvc\Router\Http\Segment
If you really need it you must extend this class (but I would not recommend that, because I think your approach is already wrong)

How to set db adapter to Validator NoRecordExists and use it in controller?

I recently started learning ZF2 and hope someone can help me with this.
I am working my way through Rob Allen's Zend Framework 2 Tutorial (many thanks to #rob-allen).
Also I use a solution of #AlloVince and #Maciej How to set db adapter to Validator RecordExists in Zend Framework 2 (many thanks to both authors for it) and I confused because didn't to use this solution in editAction.
I see Fatal error: Call to a member function get() on a non-object in 'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter').
1) In the Module.php added
public function getServiceConfig()
{
return array(
'invokables' => array(
'RegionModel' => 'FcLibraries\Model\Region', //<-- added it
),
'factories' => array(
'FcLibraries\Model\RegionTable' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new RegionTable($dbAdapter);
return $table;
},
),
);
}
2) In the Region.php added
/**
* #var
*/
protected $serviceLocator;
/**
* #param \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator
* #return Library
*/
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
/**
* #return \Zend\ServiceManager\ServiceLocatorInterface
*/
public function getServiceLocator()
{
return $this->serviceLocator;
}
and
$inputFilter->add($factory->createInput(array(
'name' => 'name',
'required' => true,
'filters' => $this->_filters,
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => $this->table,
'field' => 'name',
//'exclude' => array(
// 'field' => 'id',
// 'value' => $this->id
//),
'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter'),
),
),
),
)));
3) In the RegionController.php in addAction using
$model = $this->getServiceLocator()->get('RegionModel');
instead of $model = new Region();.
This works fine for addAction, But I can not understand how I should use it in editAction.
My
public function editAction()
{
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('zfcadmin/region', array(
'action' => 'add'
));
}
$data = $this->getRegionTable()->get($id);
$form = new RegionForm();
$form->bind($data);
$form->get('submitBtn')->setAttribute('value', 'Save');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($data->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
My RegionTable has the following code:
/**
* #param \Zend\Db\Adapter\Adapter $adapter
*/
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new Region());
$this->initialize();
}
public function get($id)
{
$id = (int)$id;
$rowSet = $this->select(array('id' => $id));
$row = $rowSet->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
Many thanks to all who will answer my question.
Best regards, Ruslan.
Instead of using the form filter from the entity which you gathered from the table you should instantiate a new entity via the service manager to use the database adapter.
You have a few options:
Move the input filter to its own class and instantiate via the service manager so your database adapter is injected.
Change the prototype object in the table gateway factory to be instantiated via the service manager factory.
Instantiate a separate entity via the service manager and get the input filter from there.
I personally would go for option 1 as it separates the code better.
Some examples:
Option 1 (my choice):
This involves moving the filter to its own file and class, creating a factory for it whilst injecting the database adapter. We will then, in the controller, get the filter via the service manager and apply the filter to the form.
So first move your filter to a file in ModName\src\ModName\Form\RegionFilter.php, obviosly replacing ModName with your module name.
and change the code to like so:
<?php
namespace Region\Form;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Db\Adapter\Adapter;
class RegionFilter implements InputFilterAwareInterface {
/**
* #var inputFilter
*/
protected $inputFilter;
/**
* #var Database Adapter
*/
protected $dbAdapter;
/**
* #param \Zend\InputFilter\InputFilterInterface $inputFilter
* #throws \Exception
*/
public function setInputFilter(InputFilterInterface $inputFilter) {
throw new \Exception("Not used");
}
/**
* #param \Zend\Db\Adapter $dbAdapter
*/
public function __construct(Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
}
/**
*
* #return Zend\Db\Adapter
*/
public function getDbAdapter() {
return $this->dbAdapter;
}
/**
* #return \Zend\InputFilter\InputFilter
*
* Get the input filter (build it first)
*/
public function getInputFilter() {
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'name',
'required' => true,
'filters' => $this->_filters,
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => $this->table,
'field' => 'name',
//'exclude' => array(
// 'field' => 'id',
// 'value' => $this->id
//),
'adapter' => $this->getDbAdapter(),
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
?>
You would then create a factory like so in Module.php:
public function getServiceConfig()
{
return array(
'factories' => array(
'ModName\Form\RegionFilter' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
return new RegionFilter($dbAdapter);
},
),
);
}
And finally in your controller, just do the following:
if ($request->isPost()) {
$filter = $this->getServiceLocator()->get('ModName\Form\RegionFilter');
$form->setInputFilter($filter->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
Option 2:
This involves constructing your table with an instance of Region injected. Then you can set the prototype to this.
So in your table construct:
public function __construct(Adapter $adapter, Region $region)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype($region);
$this->initialize();
}
And then your factory:
public function getServiceConfig()
{
return array(
'invokables' => array(
'RegionModel' => 'FcLibraries\Model\Region',
),
'factories' => array(
'FcLibraries\Model\RegionTable' => function ($sm) {
$region = $sm->get('RegionModel');
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new RegionTable($dbAdapter,$region);
return $table;
},
),
);
}
You should be able to leave the rest of the code as is. Eg the controller. Now I have not tested this method so I'm not 100% it will work, but I think it should. The other two methods I have used previously myself.
Option 3 (the simplest):
This involves getting a separate region model via the service manager and using that to apply the input filter to the form.
public function editAction()
{
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('zfcadmin/region', array(
'action' => 'add'
));
}
$data = $this->getRegionTable()->get($id);
$form = new RegionForm();
$form->bind($data);
$form->get('submitBtn')->setAttribute('value', 'Save');
$request = $this->getRequest();
if ($request->isPost()) {
$region = $this->getServiceLocator()->get('RegionModel');
$form->setInputFilter($region->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
I have not tested the code but you should get the gist. Any questions just ask.
For doing the validation for "Username already exists or not", Do the following simple way of Service Manager config settings like:
// config/autoload/global.php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2tutorial;host=localhost',
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => function ($serviceManager) {
$adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
$adapter = $adapterFactory->createService($serviceManager);
\Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);
return $adapter;
}
),
)
);
and add the following array into getInputFilter():
array(
'table' => 'users',
'field' => 'username',
'adapter' => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter();
)

Resources