How to retrieve the Zend_Config used by Zend_Application? - zend-framework

I'm migrating my app to use Zend_Application for bootstrap. I used to have the Zend_Config as a key for my $registry.
Now I don't know how to use it this way anymore (without having to reload the config file).
I know it's possible to use $application->getOptions(), but that gives my an array and I would have to change everywhere in my code where $config is used like an object ($config->services->storage) to array-like ($config['services']['storage']).

Zend_Registry::set('config', new Zend_Config($this->getOptions()));
is all you need.

Zend_Application only uses (and stores) the config.ini file, as given in the second parameter of the call to 'new Zend_Application(ENV, '.../app.ini');' as an array. To be able to store it as an object, you'll have to re-parse it.
You can add a function into the bootstrap to do so, and store it into the registry,
<?php
// in 'class Bootstrap extends Zend_Application_Bootstrap_Bootstrap'
protected function _initConfig()
{
// config
//#Zend_Registry::set('config', $this->getOptions()); // as an array
$ZFOptions = array(); // could be: 'allowModifications'=>true
$section = 'production'; // or from the environment
$configFilename = APPLICATION_PATH .'/configs/application.ini';
$config = new Zend_Config_Ini($configFilename, $section, $ZFOptions);
Zend_Registry::set('config', $config); // as an object
}

Related

Wordpress Plugins / Custom Class / get_option() / shortcode

I'm having an issue displaying information returned from a custom class defined within a plugin's files, when using a shortcode. I'll write up some mock files that showcase my issue.
/wp-content/plugins/my-plugin/classes/my_class.php
<?php
class People {
public $api_url = "https://www.external-service.com/api";
private $api_key;
function __construct($key = null) {
if $(key) {
$this->api_key = $key;
}
function get_response() {
$path = $this->api_url . "?my_api_token=" . $this->api_key;
}
}
?>
/wp-content/plugins/my-plugin/my-plugin.php
<?php
/**
* all of the wordpress plugin comments
* ...
*/
require "myplg_options.php";
require "myplg_shortcodes.php";
The options page and menu is generated from myplg_options; it is functioning correctly (including using get_option to retrieve the saved option (in this case, the api key).
/wp-content/plugins/my-plugin/myplg_shortcodes.php
<?php
require "classes/my_class.php";
$options = get_option('myplg_settings');
$myplg = new People($options['myplg_api_key']);
$response = $myplg->get_response();
function myplg_list_result(){
echo "the shortcode is working!";
var_dump($options, $myplg, $respnose);
}
add_shortcode('myplg_list', 'myplg_list_result');
?>
Testing externally from wordpress, the class works and everything is fine and dandy. The plugin's option page sets and retains the single option perfectly; the shortcode actually registers and is usable from within a WordPress page/portfolio/etc.
The issue I'm having is that using var_dump, all three of those variables are dumped as NULL.
After doing some homework, I was able to determine that moving the three variable declarations inside the shortcode makes it work. It would seem to me, however, that doing that is not the best workflow, as I'd need to re-grab the option, instantiate a new class, and call the class' function for every shortcode.
Is there a way around this?
As mentioned in the comment it's because variables are function scoped. You may be better off using a Closure.
<?php
require "classes/my_class.php";
$options = get_option('myplg_settings');
$myplg = new People($options['myplg_api_key']);
$response = $myplg->get_response();
add_shortcode('myplg_list', function() use ($options, $response, $myplg) {
echo "the shortcode is working!";
var_dump($options, $myplg, $respnose);
});

Zend_Session not carrying values across to view

I have setup in my MVC site a Session variable to carry ids to be used on any subsequent pages.
In my controller, var_dumping the session shows its there with the correct values but when I pass said values to the view and trying to echo them there, it comes up blank.
Any pointers as to whats going on to cause them to not appear.
Please note, the view is a partial view, not the main one.
Bootstrap session related code:
protected function _initSession(){
Zend_Session::start();
$SessAuto2Auto = new Zend_Session_Namespace('SessAuto2Auto');
$SessAuto2Auto->cityIds = "1,2,3"; // Hard code values for testing purposes
$SessAuto2Auto->IndustryIds = "3,4"; // Hard code values for testing purposes
}
Controller related code : ProductController.php
public function indexAction()
{
// .. Unrelated code removed for brevity
$response = $this->getResponse();
$response->insert('sidebar', $this->view->render('sidebar.phtml'));
// This code is dumping the values correctly
echo('<pre>');
var_dump($this->sessionAuto2Auto);
echo('</pre>');
// .. Unrelated code removed for brevity
$this->view->filterCity = $this->sessionAuto2Auto['cityIds'];
$this->view->filterIndustryIds = $this->sessionAuto2Auto['IndustryIds'];
}
View partial : sidebar.phtml
<?php
// This code does NOT show the value, comes up blank
echo($this->filterCity);
?>
If you are calling sidebar.phtml using the partial helper, partials have their own variable scope, they can only access variables which are passed in to them. You need to either include your session variables in your partial helper call:
echo $this->partial('sidebar.phtml', array(
'filterCity' => $this->filterCity,
'filterIndustryIds' => $this->filterIndustryIds
)
or use render instead (which uses the same scope as the other view scripts):
<?=$this->render('sidebar.phtml')?>

Zend Framework - Form Element - Remove ID

Is it possible to remove the 'id' attribute that Zend Framework adds to every Form Element by default?
I've looked at the documentation but don't seem to be able to find an answer to this rather straight forward question.
Possible Solution
Is there any cleaner way to do it other than setOption?
$submit = new Zend_Form_Element_Submit('submit');
$submit->setRequired(FALSE)
->setIgnore(TRUE)
->setDecorators($this->elementDecorators)
->setOptions(array('id' => ''));
A solution would be to override Zend_View_Helper_Form with your own View Helper.
But sincerely, don't take too much attention to this id attribute in your form, you will sooner or later need this id (if you're using Javascript for example) and the performance gain (to render the page) is too tiny to be taken into consideration. It will even be a performance loss since you're going to override a Helper.
If your purpose is different and you want to do that anyway, you need to write you own View Helper as follow:
class My_View_Helper_Form extends Zend_View_Helper_FormElement
{
public function form($name, $attribs = null, $content = false)
{
$info = $this->_getInfo($name, $content, $attribs);
extract($info);
$xhtml = '<form'
. $this->_htmlAttribs($attribs)
. '>';
if (false !== $content) {
$xhtml .= $content
. '</form>';
}
return $xhtml;
}
}
Finally, you simply need to overload the default view helper using a plugin loader. Read the manual for more information about plugin loader.

Zend overwrite default view object

How can I overwrite the default view object in zend framework so I could have the custom one?
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
function _initViewHelpers() {
$this->bootstrap('view');
$view = $this->getResource('view');
$view->doctype('HTML4_STRICT');
$view->setHelperPath(APPLICATION_PATH . '/helpers', '');
$view->headMeta()->appendHttpEquiv('Content-type', 'text/html;charset=utf-8')
->appendName('description', 'Zend Framework');
$view->headTitle()->setSeparator(' - ');
$view->headTitle('Zend Custom View');
$view->setScriptPath(APPLICATION_PATH . '/themes/admin');
return $view;
}
}
The default view contains default script path for module. I want one path for all modules, to enable template system. The setScriptPath method should overwrite the default path generated by the view object, but it doesn't.
array(2) { [0]=> string(66) "C:/xampp/htdocs/NEOBBS_v6/application/modules/admin/views\scripts/" [1]=> string(51) "C:\xampp\htdocs\NEOBBS_v6\application/themes/admin/" }
it has two scriptPaths. Can this be done by overwriting the default view object?
What ArneRie posted is correct, however the ViewRenderer checks to see whether the standard script path is set and adds it if not. Since the paths are checked LIFO, what's happening is that the ViewRenderer is adding the standard path after your one and then always using that one.
What worked for me was to set both the standard path and my custom path at the same time, with the custom one being last, something like:
$view->setScriptPath(array(
APPLICATION_PATH . '/views/scripts/', // or whatever the standard path is
APPLICATION_PATH . '/themes/admin'
));
there may be a better solution for this though.
Try to add:
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

How do you Unit Test a Zend_Form that includes the CSRF form element?

I'm using the CSRF hidden hash element with Zend_Form and trying to Unit Test the login but don't know how to write a Unit Test to include that element. Looked in the docs and read as many tutorials as I could find. I even delicioused them all, but no one mentions this.
Csrf value is generated each time form is rendered. Hidden element of the form gets prefilled with that value. This value also gets stored in session.
After submitting form, validation checks if value posted from the form is stored in session, if not then validation fails. It is essential, that form must be rendered during the test (so it can generate the hidden value and store it to session), then we can extract what is the hidden value out of rendered html, and later we can add hidden hash value into our request.
Consider this example:
function testAddPageStoreValidData()
{
// render the page with form
$this->dispatch('/form-page');
// fetch content of the page
$html = $this->getResponse()->getBody();
// parse page content, find the hash value prefilled to the hidden element
$dom = new Zend_Dom_Query($html);
$csrf = $dom->query('#csrf')->current()->getAttribute('value');
// reset tester for one more request
$this->resetRequest()
->resetResponse();
// now include $csrf value parsed from form, to the next request
$this->request->setMethod('POST')
->setPost(array('title'=>'MyNewTitle',
'body'=>'Body',
'csrf'=>$csrf));
$this->dispatch('/form-page');
// ...
}
The correct hash is stored in the session, and the Hash form element has a Zend_Session_Namespace instance which contains the namespace for the hash.
To unit test the element, you would replace the Zend_Session_Namespace instance in the element (with setSession) with one you create yourself which contains the correct hash (the hash is stored in key "hash")
For further examples you could probably look at the Zend Framework unit tests for the Zend_Form_Element_Hash class. I would assume they have had to deal with this as well.
I set an environment variable in my Apache vhost file, which tells the code which server it's running on:
development, staging, or production
The line for the vhost file is:
SetEnv SITE_ENV "dev"
Then I just make my forms react to the appropriate environment:
if($_SERVER['SITE_ENV']!='dev')
{
$form_element->addValidator($csrf_validator);
}
I use this same technique for lots of stuff. For example, if it IS dev, I redirect all outgoing email to me, etc.
I answered a more recent question similar to this one. I'm putting my answer here as well in case it helps anybody in the future.
I recently found a great way of testing forms with hash elements. This will use a mock object to stub away the hash element and you won't have to worry about it. You won't even have to do a session_start or anything this way. You won't have to 'prerender' the form either.
First create a 'stub' class like so
class My_Form_Element_HashStub extends Zend_Form_Element_Hash
{
public function __construct(){}
}
Then, add the following to the form somewhere.
class MyForm extends Zend_Form
{
protected $_hashElement;
public function setHashElement( Zend_Form_Hash_Element $hash )
{
$this->_hashElement = $hash;
return $this;
}
protected function _getHashElement( $name = 'hashElement' )
{
if( !isset( $this->_hashElement )
{
if( isset( $name ) )
{
$element = new Zend_Form_Element_Hash( $name,
array( 'id' => $name ) );
}
else
{
$element = new Zend_Form_Element_Hash( 'hashElement',
array( 'id' => 'hashElement' ) );
}
$this->setHashElement( $element );
return $this->_hashElement;
}
}
/**
* In your init method you can now add the hash element like below
*/
public function init()
{
//other code
$this->addElement( $this->_getHashElement( 'myotherhashelementname' );
//other code
}
}
The set method is there just for testing purposes really. You probably won't use it at all during real use but now in phpunit you can right the following.
class My_Form_LoginTest extends PHPUnit_Framework_TestCase
{
/**
*
* #var My_Form_Login
*/
protected $_form;
/**
*
* #var PHPUnit_Framework_MockObject_MockObject
*/
protected $_hash;
public function setUp()
{
parent::setUp();
$this->_hash = $this->getMock( 'My_Form_Element_HashStub' );
$this->_form = new My_Form_Login( array(
'action' => '/',
'hashElement' => $this->_hash
}
public function testTrue()
{
//The hash element will now always validate to true
$this->_hash
->expects( $this->any() )
->method( 'isValid' )
->will( $this->returnValue( true ) );
//OR if you need it to validate to false
$this->_hash
->expects( $this->any() )
->method( 'isValid' )
->will( $this->returnValue( true ) );
}
}
You HAVE to create your own stub. You can't just call the phpunit method getMockObject() because that will directly extend the hash element and the normal hash element does 'evil' stuff in its constructor.
With this method you don't even need to be connected to a database to test your forms! It took me a while to think of this.
If you want, you can push the setHashElement() method ( along with the variable and the get method ) into some FormAbstract base class.
REMEMBER, in phpunit you HAVE to pass the hash element during form construction. If you don't, your init() method will get called before your stub hash can be set with the set method and you'll end up using the regular hash element. You'll know you're using the regular hash element because you'll probably get some session error if you're NOT connected to a database.
Let me know if you find this helpful or if you use it.
Solution for ZF2 is creating your form in test, and getting value from your csrf form element:
$form = new \User\Form\SignupForm('create-user');
$data = [
'security' => $form->get('security')->getValue(),
'email' => 'test#test.com',
'password' => '123456',
'repeat-password' => '123456',
];
$this->dispatch('/signup', 'POST', $data);