How to use Session Container in controller action? - zend-framework2

I was searching on internet. I want to use session in Action. And I have codes:
in module.config.php:
return array(
'remember_me_seconds' => 360,
'name' => 'zf2',
'use_cookies' => true,
'cookie_httponly' => true,
),
);
in Module.php
public function onBootstrap(MvcEvent $e)
{
$config = $e->getApplication()->getServiceManager()->get('Configuration');
$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config['session']);
$sessionManager = new SessionManager($sessionConfig);
$sessionManager->start();
/**
* Optional: If you later want to use namespaces, you can already store the
* Manager in the shared (static) Container (=namespace) field
*/
Container::setDefaultManager($sessionManager);
}
In Controller:
public function updatesessionAction(){
$key = $this->getEvent()->getRouteMatch()->getParam('key');
$value = $this->getEvent()->getRouteMatch()->getParam('value');
$this->userSession = new Container($this->sessionNameSpace);
$this->userSession->offsetSet($key,$value);
}
It run, but time expired always = 180 seconds. Not 360 seconds like i config.
I don't know the where have value 180. And what do i need to set it like config ?

Related

ZF2 use view helper in Validator class

UPDATED!
ZF2, l10n view helper. I can't understand how to use my view helper inside of a class.
I want to use it like: $this->t('STRING TO TRANSLATE');
example bellow
NB! i'm only localizing project, i'm not allowed to change code structure or smth like that.Also i'm absolute newb in ZF2.
my Class -
class Project extends InputFilter{
as i understood i have to implement ServiceLocatorAwareInterface interface, tried this:
use Zend\ServiceManager\ServiceLocatorInterface as ServiceLocator;
class Project extends InputFilter implements ServiceLocator
{
protected $services;
public function __construct(Connection $p4, $mode, ServiceLocator $services)
{
$this->services = $services;
//some code
$this->add(...);
$this->add(
array(
'name' => 'name',
'filters' => array('trim'),
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'message' => "Name is required and can't be empty."
)
),
array(
'name' => '\Application\Validator\Callback',
'options' => array(
'callback' => function ($value) use ($p4, $toId, $mode, $reserved) {
$id = $toId($value);
if (!$id) {
return $this->t('STRING TO TRANSLATE');
}
// more code here
return true;
}
)
)
)
)
);
//some code
$this->add(...);
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator() {
return $this->serviceLocator;
}
//how to get this method work ???
public function t($msg) {
$translate = $this->services->get('ViewHelperManager')->get('t');
return $translate($msg);
}
}
Usage in Controller:
use Projects\Filter\Project as ProjectFilter;
...
protected function doAddEdit($mode, $project = null)
{
$p4Admin = $this->getServiceLocator()->get('p4_admin');
$request = $this->getRequest();
// process add request.
if ($request->isPost()) {
// pull out the data
$data = $request->getPost();
// configure our filter with the p4 connection and add/edit mode
$filter = new ProjectFilter($p4Admin, $mode); //
$filter->setData($data);
// if the data is valid, setup the project and save it
$isValid = $filter->isValid();
if ($isValid) {
$values = $filter->getValues();
$project = new Project($p4Admin);
$project->set($values)
->save();
}
return new JsonModel(
array(
'isValid' => $isValid,
'messages' => $filter->getMessages(), // THESE array of messages i want to localize
'redirect' => '/projects/' . $filter->getValue('id')
)
);
}
// prepare view for form.
$view = new ViewModel;
$view->setVariables(
array(
'mode' => $mode,
'project' => $project ?: new Project
)
);
return $view;
}
What am i doing wrong ?
You're calling tr method inside a class constructor. tr method calls $this->getServiceLocator(). $this->getServiceLocator() will not return a service locator instance since it'll only be injected by service manager after it has created the object that implements ServiceLocatorAwareInterface.
So you'd have to pass a service locator instance to the constructor, or don't depend on it in your __construct method. Probably the easiest way to go is to move your code from the constructor to the init method. Init is supposed to get called automatically as long as you get your input filter through the InputFilterManager.
Also I don't think you need the translator view helper. You should be able to get it from the service manager like so: $serviceManager->get('translator')
There is no need to do this at all the validation message will be translated by the validator anyway. But your config is a bit wrong I think
$this->add(
array(
'name' => 'name',
'filters' => array('trim'),)
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'YOUR_TRANSLATION_STRING_IS_EMPTY',
\Zend\Validator\NotEmpty::INVALID => 'YOUR_TRANSLATION_STRING_INVALID',
)
)
)
),
Have a read of https://zf2-docs.readthedocs.org/en/latest/modules/zend.validator.html#translating-messages
You will need to ensure you are managing your dependencies correctly for this to work so really depends how you are using the input filter.
If your not directly adding to a form or using InputFilterAwareInterface on your model you'll need to make sure your InputFilter is registered with InputFilterPluginManager and you retrieve it using InputFilterPluginManager rather than instantiating directly

Dynamically loading ZF2 Modules

I have following application.config
return array(
'modules' => array(
'Application',
'ErrorHandler'
),
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor'
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php'
)
)
);
and in the Application/Module.php I have (few of the functions):
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$this->initModules($e);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
private function getModules(MvcEvent $e) {
$sm = $e->getApplication()->getServiceManager();
$moduleTable = $sm->get('ModuleTable');
$modules = array();
foreach ($moduleTable->fetchAll() as $m) {
$modules[] = $m;
}
return $modules;
}
private function initModules(MvcEvent $e) {
$modules = $this->getModules($e);
$serviceManager = $e->getApplication()->getServiceManager();
$moduleManager = $serviceManager->get('ModuleManager');
$loadedModules = $moduleManager->getLoadedModules();
foreach ($loadedModules as $module) {
$this->loadedModules[] = str_replace('\Module', '', get_class($module));
}
foreach ($modules as $module) {
try {
$moduleManager->loadModule($module->getName());
$this->loadedModules[] = $module->getName();
} catch (\Exception $e) {
$this->failedModules[] = $module->getName();
}
}
if (count($this->failedModules) > 0) {
// Error in loading modules
exit;
}
return $this;
}
public function getServiceConfig()
{
return array(
'factories' => array(
'ModuleTable' => function($sm) {
return new ModuleTable($sm->get('Zend\Db\Adapter\Adapter'));
},
),
);
}
what I'm trying to achieve here is to have modules dynamically loaded based on a setting from database.
i get no error in loading modules ... when i try calling back $moduleManager->getLoadedModules(); i see that the module is in the loaded list but its config and its functionality doesnt work. Specifically i have routes in that module and when trying to access them i get 404. but if i include the module in the application.config all works perfect.
Possible to achieve? If yes any guidelines?
Thanks
UPDATE
I managed to get the modules dynamically loaded within the Module::init() method ... but without any success accessing the ServiceManager and/or db access to load the list of modules from db ...
This is an old question but I saw it today trying to do the exact same thing. My code is geared toward ZF3 but should work on ZF2:
https://github.com/basicinvoices/basicinvoices-modulemanager
The basics I've followed...
Wait until the modules have been loaded (ModuleEvent::EVENT_LOAD_MODULES_POST) this way we have access to the database configuration. I hooked into it with hight priority (9000) to be sure it is runned before other events.
At this point I load a Database adapter. The module services have NOT yet been assigned so we must create it by hand but it is easy. We search for active modules in the database which haven't been loaded yet and we load them with the ModuleManager::loadModule() method. We also add it to the modules array and set it back to the ModuleManager
The config is not merged and, to a certain point that is great as if the config has been cached we would have problems if the module has changed in out database... but it requires an extra step, we should check if the module has a config and, if it does, we shall merge it into the merged config ourselves.
...and that's about it.

How to change sessionid value Zend Framework 2

i want to change PHPSESSID name and value. I can could name but i couldn't change value.
i have following stracture. How i change sessionid value.
My module.config.php is
return array(
'session' => array(
'config' => array(
'class' => 'Zend\Session\Config\SessionConfig',
'options' => array(
'name' => 'portal1'
),
),
'storage' => 'Zend\Session\Storage\SessionArrayStorage',
'validators' => array(
array(
'Zend\Session\Validator\RemoteAddr',
'Zend\Session\Validator\HttpUserAgent',
),
),
),
);
My Module.php
public function onBootstrap($e) {
$this->bootstrapSession($e);
}
public function bootstrapSession($e) {
$session = $e->getApplication()
->getServiceManager()
->get('Zend\Session\SessionManager');
$session->start();
$container = new Container('initialized');
if (!isset($container->init)) {
$session->regenerateId(true);
$container->init = 1;
}
}
public function getServiceConfig() {
return array(
'factories' => array(
'Zend\Session\SessionManager' => function ($sm) {
$config = $sm->get('config');
if (isset($config['session'])) {
$session = $config['session'];
$sessionConfig = null;
if (isset($session['config'])) {
$class = isset($session['config']['class']) ? $session['config']['class']
: 'Zend\Session\Config\SessionConfig';
$options =
isset($session['config']['options']) ? $session['config']['options'] : array();
$sessionConfig = new $class();
$sessionConfig->setOptions($options);
}
$sessionStorage = null;
if (isset($session['storage'])) {
$class = $session['storage'];
$sessionStorage = new $class();
}
$sessionSaveHandler = null;
if (isset($session['save_handler'])) {
$sessionSaveHandler = $sm->get($session['save_handler']);
}
$sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
if (isset($session['validator'])) {
$chain = $sessionManager->getValidatorChain();
foreach ($session['validator'] as $validator) {
$validator = new $validator();
$chain->attach('session.validate', array($validator, 'isValid'));
}
}
} else {
$sessionManager = new SessionManager();
}
Container::setDefaultManager($sessionManager);
return $sessionManager;
},
),
);
}
MyController.php is; i want to change PHPSESSID key and value here.
public function loginAction() {
$container = new Container(); /*
i want to change PHPSESSID key and value
eg: portal1: fafsafg43kgfdsgfds //my sessionid value
*/
}
Well, I want to clarify something before answer the question -
What dose it means "i want to change PHPSESSID key and value"
As far I understand you want to change the "PHPSESSID" text. that means you want to call it in different name like "MySessionId" isn't it?
Actually I'm not authorized to write comment where I can ask!
Anyway, if you want to call it with different name than its not the issue of ZF its your server's PHP session settings. So, consult the session part of the server. You may get help from http://php.net/manual/en/session.configuration.php#ini.session.name OR http://php.net/manual/en/function.session-name.php
And ZF also let you change that name by Zend\Session\Config\SessionConfig class or Zend\Session\SessionManager class you have to set the preferred name by calling setName method.
Now if you want to change the value of session id (its automatically generated and save it into PHPSESSID) you may do it in ZF. Here is the code of ZF2 to set the value explicitly
$container->getManager()->setId($id); # For current session manager of your container
$container->getDefaultManager()->setId($id); # For default session manager of your entire app
In above code $id is the value you want to set.

ZF2 - get was unable to fetch or create an instance for getAlbumTable

I used the getAlbumTable in the title since the problem I'm facing is based on the Zend Album Tutorial, might be easier for others having a similar problem to find. All I've done is rename Album to "Champrallies".
My error:
Zend\Mvc\Controller\PluginManager::get was unable to fetch or create an instance for getChampralliesTable
What I'm trying to do is execute a function from a second Model I've created. I can execute from the 'original' model no problem AlbumTable or in my case ChampionshipTable. I'm trying to get data from a second table, but within the same module. The second table is called "champ_rallies" and the Model files are Champrallies.php and ChampralliesTable.php.
Changing this part in my controller
'champRallies' => $this->getChampralliesTable()->fetchAll(),
to
'champRallies' => $this->getChampionshipTable()->fetchAll(),
means the error message disappears. So my first thought is that there is something wrong with namespaces, or module.php. (Forgive me, I'm fairly new at all this)
Module.php
<?php
namespace Championship;
use Championship\Model\Championship;
use Championship\Model\ChampionshipTable;
use Championship\Model\Champrallies;
use Championship\Model\ChampralliesTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
// Add this method:
public function getServiceConfig()
{
return array(
'factories' => array(
'Championship\Model\ChampionshipTable' => function($sm) {
$tableGateway = $sm->get('ChampionshipTableGateway');
$table = new ChampionshipTable($tableGateway);
return $table;
},
'ChampionshipTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Championship());
return new TableGateway('championships', $dbAdapter, null, $resultSetPrototype);
},
'Championship\Model\ChampralliesTable' => function($sm) {
$tableGateway = $sm->get('ChampralliesTableGateway');
$table = new ChampralliesTable($tableGateway);
return $table;
},
'ChampralliesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Champrallies());
return new TableGateway('champ_rallies', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
My second thought is that perhaps I'm not declaring the right namespace, or something similar.
ChampralliesTable.php
<?php
namespace Championship\Model;
use Zend\Db\TableGateway\TableGateway;
class ChampralliesTable
Champrallies.php
<?php
namespace Championship\Model;
class Champrallies
I fear I'm overlooking something failure but I haven't found any similar posts through google or on here, any help is appreciated!
edit: I had forgotten to add getChampralliesTable function to the controller itself,
public function getChampralliesTable()
{
This is Line 50 -> if (!$this->champralliesTable) {
$sm = $this->getServiceLocator();
$this->champralliesTable = $sm->get('Championship\Model\ChampralliesTable');
}
return $this->champralliesTable;
}
But now I'm getting this,
Notice: Undefined property: Championship\Controller\ChampionshipController::$champralliesTable in /usr/home/phil/git/rallystats/module/Championship/src/Championship/Controller/ChampionshipController.php on line 50
I had forgotten to add getChampralliesTable function to the controller itself,
public function getChampralliesTable()
{
This is Line 50 -> if (!$this->champralliesTable) {
$sm = $this->getServiceLocator();
$this->champralliesTable = $sm->get('Championship\Model\ChampralliesTable');
}
return $this->champralliesTable;
}
But now I'm getting this,
Notice: Undefined property: Championship\Controller\ChampionshipController::$champralliesTable in /usr/home/phil/git/rallystats/module/Championship/src/Championship/Controller/ChampionshipController.php on line 50
Solving this was just a matter of adding
protected $champralliesTable;
to the top of my ChampionshipController.
edit: Doing the above solves my problem.

Zend FrameWork 2 Get ServiceLocator In Form and populate a drop down list

I need to get the adapter from the form, but still could not.
In my controller I can recover the adapter using the following:
// module/Users/src/Users/Controller/UsersController.php
public function getUsersTable ()
{
if (! $this->usersTable) {
$sm = $this->getServiceLocator();
$this->usersTable = $sm->get('Users\Model\UsersTable');
}
return $this->usersTable;
}
In my module I did so:
// module/Users/Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Users\Model\UsersTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$uTable = new UsersTable($dbAdapter);
return $uTable;
},
//I need to get this to the list of groups
'Users\Model\GroupsTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$gTable = new GroupsTable($dbAdapter);
return $gTable;
},
),
);
}
Could someone give me an example how to get the adapter to the table from the group form?
I have followed this example to my form users:
http://framework.zend.com/manual/2.0/en/modules/zend.form.collections.html
EDITED from here...
Maybe I expressed myself wrong to ask the question.
What I really need to do is populate a select (Drop Down) with information from my table groups.
So I need to get the services inside my userForm class by ServiceLocatorAwareInterface (see this link) implemented because By default, the Zend Framework MVC registers an initializer That will inject into the ServiceManager instance ServiceLocatorAwareInterface Implementing any class.
After retrieving the values ​​from the table groups and populate the select.
The problem is that of all the ways that I've tried, the getServiceLocator() returns this:
Call to a member function get() on a non-object in
D:\WEBSERVER\htdocs\Zend2Control\module\Users\src\Users\Form\UsersForm.php
on line 46
I just wanted to do this in my UserForm...
namespace Users\Form;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Form\Element;
use Zend\Form\Form;
class UsersForm extends Form implements ServiceLocatorAwareInterface
{
protected $serviceLocator;
public function getServiceLocator ()
{
return $this->serviceLocator;
}
public function setServiceLocator (ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function __construct ($name = null)
{
parent::__construct('users');
$this->setAttribute('method', 'post');
$sm = $this->getServiceLocator();
$groups = $sm->get('Users\Model\GroupsTable')->fetchAll(); // line 46
$select = new Element\Select('groups');
$options = array();
foreach ($groups as $group) {
$options[$group->id] = $group->name;
}
$select->setValueOptions($options);
$this->add($select);
// and more elements here...
The other various answers here generally correct, for ZF < 2.1.
Once 2.1 is out, the framework has a pretty nice solution. This more or less formalizes DrBeza's solution, ie: using an initializer, and then moving any form-bootstrapping into an init() method that is called after all dependencies have been initialized.
I've been playing with the development branch, it it works quite well.
This is the method I used to get around that issue.
firstly, you want to make your form implement ServiceLocatorInterface as you have done.
You will then still need to manually inject the service locator, and as the whole form is generated inside the contrstuctor you will need to inject via the contructor too (no ideal to build it all in the constructor though)
Module.php
/**
* Get the service Config
*
* #return array
*/
public function getServiceConfig()
{
return array(
'factories' => array(
/**
* Inject ServiceLocator into our Form
*/
'MyModule\Form\MyForm' => function($sm) {
$form = new \MyModule\Form\MyFormForm('formname', $sm);
//$form->setServiceLocator($sm);
// Alternativly you can inject the adapter/gateway directly
// just add a setter on your form object...
//$form->setAdapter($sm->get('Users\Model\GroupsTable'));
return $form;
},
),
);
}
Now inside your controller you get your form like this:
// Service locator now injected
$form = $this->getServiceLocator()->get('MyModule\Form\MyForm');
Now you will have access to the full service locator inside the form, to get hold of any other services etc such as:
$groups = $this->getServiceLocator()->get('Users\Model\GroupsTable')->fetchAll();
In module.php I create two services. See how I feed the adapter to the form.
public function getServiceConfig()
{
return array(
'factories' => array(
'db_adapter' => function($sm) {
$config = $sm->get('Configuration');
$dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
return $dbAdapter;
},
'my_amazing_form' => function ($sm) {
return new \dir\Form\SomeForm($sm->get('db_adapter'));
},
),
);
}
In the form code I use that feed to whatever:
namespace ....\Form;
use Zend\Form\Factory as FormFactory;
use Zend\Form\Form;
class SomeForm extends Form
{
public function __construct($adapter, $name = null)
{
parent::__construct($name);
$factory = new FormFactory();
if (null === $name) {
$this->setName('whatever');
}
}
}
We handle this in the model, by adding a method that accepts a form
public function buildFormSelectOptions($form, $context = null)
{
/**
* Do this this for each form element that needs options added
*/
$model = $this->getServiceManager()->get('modelProject');
if (empty($context)){
$optionRecords = $model->findAll();
} else {
/**
* other logic for $optionRecords
*/
}
$options = array('value'=>'', 'label'=>'Choose a Project');
foreach ($optionRecords as $option) {
$options[] = array('value'=>$option->getId(), 'label'=>$option->getName());
}
$form->get('project')->setAttribute('options', $options);
}
As the form is passed by reference, we can do something like this in the controller where the form is built:
$builder = new AnnotationBuilder();
$form = $builder->createForm($myEntity);
$myModel->buildFormSelectOptions($form, $myEntity);
$form->add(array(
'name' => 'submitbutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit',
'id' => 'submitbutton',
),
));
$form->add(array(
'name' => 'cancel',
'attributes' => array(
'type' => 'submit',
'value' => 'Cancel',
'id' => 'cancel',
),
));
Note: The example assumes the base form is build via annotations, but it doesn't matter how you create the initial form.
An alternative method to the other answers would be to create a ServiceManager Initializer.
An example of an existing Initializer is how the ServiceManager is injected if your instance implements ServiceLocatorAwareInterface.
The idea would be to create an interface that you check for in your Initialiser, this interface may look like:
interface FormServiceAwareInterface
{
public function init();
public function setServiceManager(ServiceManager $serviceManager);
}
An example of what your Initializer may look like:
class FormInitializer implements InitializerInterface
{
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if (!$instance instanceof FormServiceAwareInterface)
{
return;
}
$instance->setServiceManager($serviceLocator);
$instance->init();
}
}
Anything that happens in init() would have access to the ServiceManager. Of course you would need to add your initializer to your SM configuration.
It is not perfect but it works fine for my needs and can also be applied to any Fieldsets pulled from the ServiceManager.
This is the way I used get around that issue.
firstly, In Module.php, create the service (just as you have done):
// module/Users/Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Users\Model\UsersTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$uTable = new UsersTable($dbAdapter);
return $uTable;
},
//I need to get this to the list of groups
'Users\Model\GroupsTable' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$gTable = new GroupsTable($dbAdapter);
return $gTable;
},
),
);
}
Then in the controller, I got a reference to the Service:
$users = $this->getServiceLocator()->get('Test\Model\TestGroupTable')->fetchAll();
$options = array();
foreach ($users as $user)
$options[$user->id] = $user->name;
//get the form element
$form->get('user_id')->setValueOptions($options);
And viola, that work.

Resources