Where is the best place to create a class that contain all the application constant variables ?
is it :
- Bootstrap
- In the Application Common library
for example :
1- When i retrieve an image name from a database if this record doesnt have an image , i want to put a default value somewhere so i can use it in my models
** a constants that i use in all my application so if i change it , i dont want to go back to all in my code and change it everywhere
application.ini is the best place for example define some constant there
constants.PUBLIC_PATH = APPLICATION_PATH "/../public/"
constants.THEME = blue
Then in your bootstrap do
protected function setConstants($constants)
{
foreach($constants as $name => $value)
{
if(!defined($name))
define($name, $value);
}
}
ZF take 'constants' from config and call setConstants method in your bootstrap passing all lines prefixed by constants hence its an array .
I try not use constants and prefer class constants over global constants. However, when constants are unavoidable, for whatever reason, I go with .ini config file and Bootstrap/library/model class constants.
An example of .ini config constants
(assumes default zf project structure)
application/configs/application.ini
constants.MESSAGE_1 = "Message 1"
constants.MESSAGE_2 = "Message 2"
Bootstap.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initConstants()
{
$options = $this->getOption('constants');
if (is_array($options)) {
foreach($options as $key => $value) {
if(!defined($key)) {
define($key, $value);
}
}
}
}
// ...
}
Example usage in controller:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->message1 = MESSAGE_1;
$this->view->message2 = MESSAGE_2;
}
}
I would extend on the above to allow configuration of how your constants are defined. For example you may want all constants UPPERCASED or not, and allow or disallow already defined constants, so:
application/configs/application.ini
constants.forceUppercase = 1
constants.allowAlreadyDefined = 1
constants.set.message_1 = "Message 1"
constants.set.message_2 = "Message 2"
Bootstrap:
protected function _initConstants()
{
$options = $this->getOption('constants');
if (isset($options['set']) && is_array($options['set'])) {
if (isset($options['forceUppercase'])
&& (bool) $options['forceUppercase']) {
$options['set'] = array_change_key_case($options['set'], CASE_UPPER);
}
$allowAlreadyDefined = false;
if (isset($options['allowAlreadyDefined'])
&& (bool) $options['allowAlreadyDefined']) {
$allowAlreadyDefined = true;
}
foreach($options['set'] as $key => $value) {
if (!defined($key)) {
define($key, $value);
} elseif (!$allowAlreadyDefined) {
throw new InvalidArgumentException(sprintf(
"'%s' already defined!", $key));
}
}
}
}
Bootstrap class constants
Could be your own library, or model class, etc., it depends.
In the bootstrap:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
const MESSAGE_CONSTANT = "Hello World";
// ...
}
Example usage in controller:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->message = Bootstrap::MESSAGE_CONSTANT;
}
}
Related
Maybe it will be a very lame question, but i just try.
I built my own MVC framework.
In the controller, i am creating a new object, called $Object.
Object class has a private property $id, and a getter getId();
In the controller, i am creating a new View(), what is loading a template file.
So my controllers seems like this:
$View = new View('templateFile.php');
$View->Object = new Object();
$View->show();
If i am editing this in the controller, when typing $View->Object->ge... netbeans automatically try to autocomplete it to getId or offers all methods what starts with "ge".
Cool.
I am editing the template file, where the $this is the View object.
When i type, $this-> and CTLR+Space, there are no suggession.
Is it possible to earn this somehow?
That could be a dream, if i could do this with $this->Object-> and CTRL+Space.
Here are my important pieces of my View class:
public function show() {
echo $this->getViewContent();
}
public function getViewContent() {
$container = null;
$defaultViewHeader = '';
if ($this->showDefaultViewHeader) {
if (file_exists($this->viewsDir . $this->defaultViewHeaderFile)) {
$defaultViewHeader = $this->getContent($this->viewsDir . $this->defaultViewHeaderFile);
} else {
$defaultViewHeader = $this->getContent($this->commonDir . $this->defaultViewHeaderFile);
}
}
$pageContent = $this->getContent($this->file);
if ($this->showDefaultViewHeader) {
$pageContent = $defaultViewHeader . $pageContent;
}
if ($this->showContainer) {
$container = $this->getContent($this->viewsDir . $this->containerFile);
$pageContent = str_replace('[' . HTD_PAGECONTENT . ']', $pageContent, $container);
}
return $pageContent;
}
public function getContent($file) {
ob_start();
include ($file);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
You could specify a variable type to netbeans using the "var" annotation.
Try to add this line into your template :
/* #var $this View */
More on this here https://blogs.oracle.com/netbeansphp/entry/defining_a_variable_type_in
I am trying to call model methods from controller. but I am getting Fatal error: Class 'GuestModel' not found in. error
following is the code ::
Controller ::
class GuestController extends Zend_Controller_Action
{
public function indexAction(){
$guestbook = new GuestModel();
$this->view->entries = $guestbook->fetchAll();
}
}
Model::
class GuestModel extends Zend_Db_Table_Abstract
{
public function fetchAll()
{
$resultSet = $this->getDbTable()->fetchAll();
$entries = array();
foreach ($resultSet as $row) {
$entry = new Application_Model_Guestbook();
$entry->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
$entries[] = $entry;
}
return $entries;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Guestbook');
}
return $this->_dbTable;
}
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
}
Zend Framework autoload depends on using the correct directory structure and file naming conventions to find the classes automagically, from the looks of your code my guess would be you're not following it.
I see 2 possible solutions for your problem:
If possible, rename your class to Application_Model_Guestbook, the file to Guestbook.php and make sure to move it to your application/models/ directory. Then you just need to call it in your controller as $guestbook = new Application_Model_Guestbook();. Check this documentation example;
Create your own additional autoloading rules. Check the official documentation regarding Resource Autoloading.
I have made module Admin. In this module, in controller I have called form
class Admin_AdminController extends Zend_Controller_Action
{
public function indexAction()
{
//$form = new Application_Form_Login();
$form = new Admin_Form_Admin();
$this->view->form = $form;
}
}
But In controller its giving error -> Class 'Admin_Form_Admin' not found in application\modules\Admin\controllers\AdminController.php
My forms is in application\modules\Admin\forms\Admin.php.Below is my form code
class Admin_Form_Admin extends Zend_Form
{
public function init()
{
this->setMethod('post');
/* Form Elements & Other Definitions Here ... */
$user = $this ->CreateElement('text','username');
$password = $this->createElement('text','password');
$login = $this->createElement('submit','button');
$this->addElements(array($user,
$password,
$login
));
}
}
Three things are required here...
You need to bootstrap the modules resource
; application.ini
resources.modules[] =
You need to set the modules directory in your front controller
; application.ini
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
You need a bootstrap class in your admin module
<?php
// application/modules/Admin/Bootstrap.php
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap {}
With these three things in place, your code should work as-is.
My helper file Acl.php is in library/Helper and I have included it in bootstrap file as below:-
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initPlugins()
{
$helper= new Helper_Acl();
// $helper->setRoles();
// $helper->setResources();
// $helper->setPrivilages();
// $helper->setAcl();
}
}
but its giving error, Saying -> Fatal error: Class 'Helper_Acl' not found in Bootstrap.php.
Below is my helper file
class Helper_Acl
{
public $acl;
public function __construct()
{
$this->acl = new Zend_Acl();
}
}
in the bootstrap.php , try this , provided your class is in a Helper folder in the library :
protected function _initHelpers() {
Zend_Controller_Action_HelperBroker::addPrefix("Helper_");
}
if it doesnt work tell me , there are other methods.
You need to add Helper_ to your autoloadernamespaces. Typically, this is done in application/configs/application.ini:
autoloadernamespaces[] = "Helper_"
I'm trying to find a way to test a abstract class constant that must exist and match/not match a value. Example:
// to be extended by ExternalSDKClild
abstract class ExternalSDK {
const VERSION = '3.1.1.';
}
class foo extends AController {
public function init() {
if ( ExternalSDK::VERSION !== '3.1.1' ) {
throw new Exception('Wrong ExternalSDK version!');
}
$this->setExternalSDKChild(new ExternalSDKChild());
}
}
Limitations... The framework we use doesn't allow dependency injection in the init() method. (Suggestion to refactor the init() method could be the way to go...)
The unit tests and code coverage I have run, cover all but the Exception. I can't figure out a way to make the ExternalSDK::Version to be different from what it is.
All thoughts welcome
First, refactor the call to new into a separate method.
Second, add a method to acquire the version instead of accessing the constant directly. Class constants in PHP are compiled into the file when parsed and cannot be changed.* Since they are accessed statically, there's no way to override it without swapping in a different class declaration with the same name. The only way to do that using standard PHP is to run the test in a separate process which is very expensive.
class ExternalSDK {
const VERSION = '3.1.1';
public function getVersion() {
return static::VERSION;
}
}
class foo extends AController {
public function init() {
$sdk = $this->createSDK();
if ( $sdk->getVersion() !== '3.1.1' ) {
throw new Exception('Wrong ExternalSDK version!');
}
$this->setExternalSDKChild($sdk);
}
public function createSDK() {
return new ExternalSDKChild();
}
}
And now for the unit test.
class NewerSDK extends ExternalSDK {
const VERSION = '3.1.2';
}
/**
* #expectedException Exception
*/
function testInitFailsWhenVersionIsDifferent() {
$sdk = new NewerSDK();
$foo = $this->getMock('foo', array('createSDK'));
$foo->expects($this->once())
->method('createSDK')
->will($this->returnValue($sdk));
$foo->init();
}
*Runkit provides runkit_constant_redefine() which may work here. You'll need to catch the exception manually instead of using #expectedException so you can reset the constant back to the correct value. Or you can do it in tearDown().
function testInitFailsWhenVersionIsDifferent() {
try {
runkit_constant_redefine('ExternalSDK::VERSION', '3.1.0');
$foo = new foo();
$foo->init();
$failed = true;
}
catch (Exception $e) {
$failed = false;
}
runkit_constant_redefine('ExternalSDK::VERSION', '3.1.1');
if ($failed) {
self::fail('Failed to detect incorrect SDK version.');
}
}