Hosted on Heroku
Yii 1.14
PHP 5.6
A stranger error when Yii::app()->user->id returns the id sometimes but at other times returns empty. The same page load results in this strange behaviour.
I check for this in a parent class called AdminController.php
class AdminController extends CController
{
public $partnerCount;
public $vendorCount;
public $plantationMarkers;
public function init()
{
echo Yii::app()->user->id;
if(empty(Yii::app()->user->id)) {
echo 'User id empty: '. Yii::app()->user->id;
//$this->redirect(Yii::app()->createAbsoluteUrl('admin/auth/login'));
exit;
return false;
}
elseif(!Yii::app()->user->checkAccess(User::PARTNER)) {
$this->layout = 'column1';
$this->render('/auth/not-authorized');
return false;
}
$this->partnerCount = $this->getPartnerCount();
$this->vendorCount = $this->getVendorCount();
$this->plantationMarkers = $this->getPlantationMarkers();
return true;
}
So in this code 'User id empty: ' is echoed in some cases while in other cases I get the id.
The point is with no change in code how can this work at some time while not at other times.
Solved by changing the session to be stored in DB table. I am not sure but there was some issue with Yii storing session on the server under Heroku.
The change is required in the config array under 'components'.
From :
'session' => array(
'class' => 'CHttpSession',
'timeout' => 2400,
'cookieParams' => array(
'httpOnly' => true,
'secure' => false,
),
),
To :
'session' => array(
'timeout' => 2400,
'cookieParams' => array(
'httpOnly' => true,
'secure' => false,
),
'class' => 'CDbHttpSession',
'connectionID' => 'db',
'sessionTableName' => 'lig_session',
),
Related
I know I can do a redirect to a url after a successful user login:
return $this->redirect()->toUrl('/user/login?redirect=http://www.myurl.com');
Now, I'd like to do the same thing to a registered route instead:
'sso-post-login' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/sso-post-login',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'sso-post-login',
),
'may_terminate' => true,
),
),
But the following doesn't work:
return $this->redirect()->toUrl('/user/login?redirect=/sso-post-login');
It does not hit my action:
public function ssoPostLoginAction() {
error_log("In sso post login action");
$originUrl = Common::getCookie('sso_post_login', $this->getRequest());
$sessionCookie = Common::getCookie('PHPSESSID', $this->getRequest());
if (null != $sessionCookie && null != $this->getUserService()->getAuthService()->getIdentity()) {
$email = $this->getUserService()->getAuthService()->getIdentity()->getEmail();
$jwtCredentials = $this->buildJWTLoginToken($email);
$originUrl .= "?jwt=" . $jwtCredentials;
return $this->redirect()->toUrl($originUrl);
}
}
It simply redirects to the main page after the login is done.
Is there specific reason you don't want to put full (absolute) url to redirect param?
You could do:
return $this->redirect()->toUrl("/user/login?redirect=".$this->url()->fromRoute('sso-post-login', [], ['force_canonical' => true]));
force_canonical option will generate full url (including your hostname)
I have to set up a Redis on a server to store information from Zend Framework 2.
For now, I can store information, but I can not to give them an expiration time for they naturally renew themselves after a while.
I have not found some documentations about this step and it seems to me rather obscure.
My code:
page: config/autoload/cache.global.php
return array(
'caches' => array(
'redis' => array (
'adapter' => array (
'name' => 'redis',
'lifetime' => 60, //doesn't work
'options' => array (
'server' => array (
'host' => 'x.x.x.x',
'port' => x
),
'ttl' => 10, // seems to have no effect
'namespace' => 'mycache',
),
),
)
)
);
in Controller :
..
use Zend\Cache\StorageFactory;
..
$redis = StorageFactory::factory ($this->getServiceLocator ()
->get ('config')['caches']['redis']);
if ($redis->hasItem ('test')) {
var_dump($redis->getItem ('test'));
$redis->removeItem('test');
} else {
$redis->addItem('test', 'testtest');
}
..
I tried several methods, but everytime, the result is the same, no expiration information appears in Redis :
127.0.0.1:6379> get mycache:test
"testtest"
127.0.0.1:6379> ttl mycache:test
(integer) -1
Thanks for your help!
You can also try this:
$redis = $this->getServiceLocator()->get('Cache\RedisFactory');
$redis->getOptions()->setTtl(10);
$redis->setItem('test', 'Custom Value');
So there is no need to set it globaly in factory.
This work for me :)
Take a look at my redis factory bellow:
<?php
namespace Application\Service\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Cache\Storage\Adapter\RedisOptions;
use Zend\Cache\Storage\Adapter\Redis;
class RedisCacheFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
$config = $config['redis'];
$options = new RedisOptions();
$options->setServer(
[
'host' => $config["host"],
'port' => $config["port"],
'timeout' => $config["timeout"]
]
);
$options->setTtl(60);
/**
* This is not required, although it will allow to store anything that can be serialized by PHP in Redis
*/
$options->setLibOptions(
[
\Redis::OPT_SERIALIZER => \Redis::SERIALIZER_PHP
]
);
$redis = new Redis($options);
return $redis;
}
}
As you can see from the example, the TTL is set to 60 seconds and its working as expected.
Predis\Client has a "magic call" method command executor for setEx:
$redis->setEx($key, $expireTTL, $value);
This will set key if does not exist with passed value for a custom expiration time.
This will update existing key, resetting expiration time.
Double check as you mentioned to see that everything works as expected:
127.0.0.1:6379>dump your_key
127.0.0.1:6379>ttl your_key
Hope it helps :) !
return array(
'caches' => array(
'redis' => array (
'adapter' => array (
'name' => 'redis',
'options' => array (
'server' => array (
'host' => 'x.x.x.x',
'port' => x
),
'Ttl' => 10, // Starting with capital letter
'namespace' => 'mycache',
),
),
)
)
);
Good morning,
In Symfony 1.4,
I tried to do what is explained here : Customizing layout to sfWidgetFormDoctrineChoice
But it doesn't work. Instead of adding a thumbnail, I just want to hide the <li> before the input, and in some condition disable/hide the checkbox input but show the label anyway.
When I add the renderer without argument, I get this error :
sfWidgetFormMySelectCheckbox requires the following options: 'choices'.
Here is my formatter code :
class sfWidgetFormMySelectCheckbox extends sfWidgetFormSelectCheckbox
{
public function configure($options = array(), $arguments = array())
{
parent::configure($options, $arguments);
}
protected function formatChoices($name, $value, $choices, $attributes)
{
.....
// new
$inputs[$id] = array(
'input' => sprintf('| test | %s',
$this->renderTag('input', array_merge($baseAttributes, $attributes))
),
'label' => $this->renderContentTag('label', self::escapeOnce($option), array('for' => $id)),
);
}
return call_user_func($this->getOption('formatter'), $this, $inputs);
}
}
And now the form where I call it :
$this->setWidget('aaa', new sfWidgetFormDoctrineChoice(array(
'model' => 'Aaa',
'expanded' => true,
'multiple' => true,
'add_empty' => false,
'query' => $query,
'renderer' => new sfWidgetFormMySelectCheckbox()
)));
Thanks for your help !
According to the docs you have to pass the choices option to the renderer object. Try something like this:
$this->setWidget('aaa', new sfWidgetFormDoctrineChoice(array(
'model' => 'Aaa',
'expanded' => true,
'multiple' => true,
'add_empty' => false,
'query' => $query,
)));
$this->widgetSchema['aaa']->setOption('renderer', new sfWidgetFormMySelectCheckbox(array(
'choices' => new sfCallable(array($this->widgetSchema['aaa'], 'getChoices'))
)));
So basically you want the renderer object get the choices from the parent widget. To do that you have to pass a sfCallable object which takes an array as the first argument in which you pass the instance of your parent widget and the name of the function getChoices.
Remember also that the expanded option is not used when you override the renderer.
I want to set the file src for my sfWidgetFormInputFileEditable from my action class which is
I tried with the following code but is always has the value which I set in Baseform only
$this->Form->setOption('file_name',array(
'file_src' => sfConfig::get('sf_upload_dir')."\\". $dirId ."\\".$this->imgName,
'is_image' => true, 'edit_mode' => true, 'delete_label' => true, 'with_delete' =>false
));
$dirid is the folder name. I can get $dirid in BaseForm so I want to overwrite the file_src from my action class.
Why the above code is not working?
You have to pass only one parameter to setOption() at a time. Or you can use setOptions() to override all options at once.
Do you have sfWidgetFormInputFileEditable in a genrated base form? I don't think so. Please do NOT edit generated base classes by hand.
Please read at least this chapter in the docs.
NOTE: Why the company id is required?
I think it should be better to put it into the form like this:
// EditSlideForm.class.php
public function configure()
{
//...
// use this if the file is optional
$this->setWidget('file_name', new sfWidgetFormInputFileEditable(array(
'file_src' => $this->getObject()->getPublicFileLocation(),
'is_image' => true,
'with_delete' => (boolean) $this->getObject()->getFile(),
'edit_mode' => !$this->isNew() && $this->getObject()->getFileName(),
)));
$this->setValidator('file_name', new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => $this->getObject()->getFileDir(),
'required' => false,
)));
$this->setValidator('file_name_delete', new sfValidatorBoolean());
// use this if the file is required
$this->setWidget('file_name', new sfWidgetFormInputFileEditable(array(
'file_src' => $this->getObject()->getPublicFileLocation(),
'is_image' => true,
'with_delete' => false,
'edit_mode' => !$this->isNew() && $this->getObject()->getFileName(),
)));
$this->setValidator('file_name', new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => $this->getObject()->getFileDir(),
)));
//...
}
This is how I usally do it. An you should add getPublicFileLocation() and getFileDir() to the model e.g.:
static public function getFileDir()
{
return sfConfig::get('sf_upload_dir') . '/slide-file';
}
public function getPublicFileLocation()
{
return str_replace(sfConfig::get('sf_web_dir'), '', self::getFileDir()) . '/' . $this->getFileName();
}
I need to create field that as option gets regex string.
So, i made PatternType field:
public function getDefaultOptions(array $options)
{
$defaultOptions = array(
'data' => null,
'data_class' => null,
'trim' => true,
'required' => true,
'read_only' => false,
'max_length' => null,
'pattern' => null,
'property_path' => null,
'by_reference' => true,
'error_bubbling' => false,
'regexp' => false,
'error_mapping' => array(),
'label' => null,
'attr' => array(),
'invalid_message' => 'This value is not valid',
'invalid_message_parameters' => array()
);
$class = isset($options['data_class']) ? $options['data_class'] : null;
// If no data class is set explicitly and an object is passed as data,
// use the class of that object as data class
if (!$class && isset($options['data']) && is_object($options['data'])) {
$defaultOptions['data_class'] = $class = get_class($options['data']);
}
if ($class) {
$defaultOptions['empty_data'] = function () use ($class) {
return new $class();
};
} else {
$defaultOptions['empty_data'] = '';
}
$patt = $options['regexp'];
unset($options['regexp']);
$defaultOptions['validation_constraint'] = new Regex(
array(
'pattern' => $patt,
'match' => true,
'message' => 'Niewłaściwy format'
)
);
var_dump($defaultOptions);
return $defaultOptions;
}
var_dump returns well formatted settings array, with regex object within - but when form is generated validation doesn't work - pass any value. Any idea why?
Why are you doing this? There is a regex validator already. Just use a normal text field with that validator.
In case you need a form without a model class to bind to, read the corresponding section.
Ok, I found what was wrong - you can only add validator constant to root form object (others symfony simply ignore). So it seems that what I need is simply get root form, add there validator_constant with validator_group option set. Then just assign field proper validator_group.