Probable reasons why autoloading wont work in Zend Framework 1.10.2? - zend-framework

Iam writing an application using Zend Framework 1.10.2.
I created few model classes and a controller to process them.
When Iam executing my application and accessing the admin controller. Iam seeing this error.
Fatal error: Class 'Application_Model_DbTable_Users' not found in C:\xampp\htdocs\bidpopo\application\controllers\AdminController.php on line 16
The error clearly shows its an autoloading error.
Hence I wrote this code in the bootstrap file.
protected function initAutoload()
{
$modeLoader = new Zend_Application_Module_AutoLoader(array
('namespace'=>'','basePath'=>APPLICATION_PATH ));
//echo(APPLICATION_PATH);
return $modeLoader;
}
Still the error remains :( . Can anyone suggest me what Iam missing out here?
This is the location of the Model Users class.
C:\xampp\htdocs\bidpopo\application\models\DbTable\Users.php
This is its code.
class Application_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
//put your code here
protected $_name='users';
public function getUser($id)
{
$id = (int)$id;
$row = $this->fetchrow('id='.$id);
if(!$row)
{throw new Exception("Could not find row id - $id");}
return $row->toArray();
}
public function addUser($userDetailArray)
{
$this->insert($userDetailsArray);
}
public function updateUser($id,$userDetailArray)
{
$this->update($userDetailArray,'id='.(int)$id);
}
public function deleteUser($id)
{
$this->delete('id='. (int)$id);
}
}
This is the Admin Controller's code
class AdminController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$this->view->title= "All Users";
$this->view->headTitle($this->view->title);
$users = new Application_Model_DbTable_Users();
$this->view->users = $users->fetchAll();
}
public function addUserAction()
{
// action body
}
public function editUserAction()
{
// action body
}
public function deleteUserAction()
{
// action body
}

You application classes don't follow the proper naming convention for the namespace you've set. The Zend_Application_Module_AutoLoader is a little different than the normal autoloader in that it doesn't simply change the '_' in the class name with '/'. It looks at the second part of the class name and then checks a folder for the existence of the class based on that.
You need to change the line:
$modeLoader = new Zend_Application_Module_AutoLoader(array(
'namespace'=>'Application',
'basePath'=>APPLICATION_PATH
));
This means it will autoload all module classes prefixed with 'Application_'. When it the second part of the class is 'Model_' it will look in "{$basePath}/models" for the class. The '_' in the rest of the class name will be replaced with '/'. So the file path of the file will be "{$basePath}/models/DbTable/Users.php".
Read more here.

Related

Using my own service with Laravel4

In my app, I was testing Google Directions API with ajax, but since I was just testing all the logic was in the routes.php file. Now I want to do things the proper way and have three layers: route, controller and service.
So in the routes I tell Laravel which method should be executed:
Route::get('/search', 'DirectionsAPIController#search');
And the method just returns what the service is supposed to return:
class DirectionsAPIController extends BaseController {
public function search() {
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
I created the service in app/libraries/Services/Directions and called it DirectionsSearchService.php and copied all the logic I developed in routes:
class DirectionsSearchService {
public function search($input = array()) {
$origin = $input['origin'];
$destination = $input['destination'];
$mode = $input['mode'];
// do stuf...
return $data;
}
}
I read the docs and some place else (and this too) and did what I was supposed to do to register a service:
class DirectionsAPIController extends BaseController {
public function search() {
App::register('libraries\Services\Directions\DirectionsSearchService');
$directionsSearchService = new DirectionsSearchService();
return $directionsSearchService->search(Input::all());
}
}
// app/libraries/Services/Directions/DirectionsSearchService.php
use Illuminate\Support\ServiceProvider;
class DirectionsSearchService extends ServiceProvider {
}
I also tried adding libraries\Services\Directions\DirectionsSearchService to the providers array in app/config/app.php.
However, I am getting this error:
HP Fatal error: Class
'libraries\Services\Directions\DirectionsSearchService' not found in
/home/user/www/my-app-laravel/bootstrap/compiled.php on line 549
What am I doing wrong? And what is the usual way to use your own services? I don't want to place all the logic in the controller...
2 main things that you are missing:
There is a difference between a ServiceProvider and your class. A service provider in Laravel tells Laravel where to go look for the service, but it does not contain the service logic itself. So DirectionsSearchService should not be both, imho.
You need to register your classes with composer.json so that autoloader knows that your class exists.
To keep it simple I'll go with Laravel IoC's automatic resolution and not using a service provider for now.
app/libraries/Services/Directions/DirectionsSearchService.php:
namespace Services\Directions;
class DirectionsSearchService
{
public function search($input = array())
{
// Your search logic
}
}
You might notice that DirectionsSearchService does not extend anything. Your service becomes very loosely coupled.
And in your DirectionsAPIController.php you do:
class DirectionsAPIController extends BaseController
{
protected $directionsSearchService;
public function __construct(Services\Directions\DirectionsSearchService $directionsSearchService)
{
$this->directionsSearchService = $directionsSearchService;
}
public function search()
{
return $this->directionsSearchService->search(Input::all());
}
}
With the code above, when Laravel tries to __construct() your controller, it will look for Services\Directions\DirectionsSearchService and injects into the controller for you automatically. In the constructor, we simply need to set it to an instance variable so your search() can use it when needed.
The second thing that you are missing is to register your classes with composer's autoload. Do this by adding to composer.json's autoload section:
"autoload": {
"classmap": [
... // Laravel's default classmap autoloads
],
"psr-4": {
"Services\\": "app/libraries/Services"
}
}
And do a composer dump-autoload after making changes to composer.json. And your code should be working again.
The suggestion above can also be better with a service provider and coding to the interface. It would make it easier to control what to inject into your controller, and hence easier to create and inject in a mock for testing.
It involves quite a few more steps so I won't mention that here, but you can read more in Exploring Laravel’s IoC container and Laravel 4 Controller Testing.

Zend: Action helper not found

I am trying to create a helper of my own. The Safecheck folder is located in the library folder and contains a Helper folder. The class is called Safecheck_Helper_Authority.php (inside library/Safecheck/Helper).
In Bootstrap.php:
protected function _initHelper()
{
Zend_Controller_Action_HelperBroker::addPrefix('Safecheck_Helper');
}
In Safecheck_Helper_Authority.php:
class Safecheck_Helper_Authority extends Zend_Controller_Action_Helper_Abstract
{
public function hasAuthority($userId, array $ids)
{
}
}
I want to user the functions inside this class. But I get the error "Message: Action Helper by name Authority not found", triggered by the following code:
$this->_helper->authority('hasAuthority');
Maybe I am not calling it with the right code? Am I missing something?
in order to call an action helper in this manner $this->_helper->authority('hasAuthority'); you need to define the direct() method in your helper.
class Safecheck_Helper_Authority extends Zend_Controller_Action_Helper_Abstract
{
public function direct($userId, array $ids)
{
// do helper stuff here
}
}
an easy way to register the helper path and prefix is to use the application.ini:
resources.frontController.actionhelperpaths.Safecheck_Helper = APPLICATION_PATH "/../library/Safecheck/Helper"
to do it in bootstrap (not sure if addPrefix() works with library namespaces):
protected function _initHelper()
{
//addPath(path_to_helper, helper_prefix)
Zend_Controller_Action_HelperBroker::addPath('/../library/Safecheck/Helper', 'Safecheck_Helper');
}
a Simple example of an action helper:
class Controller_Action_Helper_Login extends Zend_Controller_Action_Helper_Abstract
{
//prepares a login form for display
public function direct()
{
$form = new Application_Form_Login();
$form->setAction('/index/login');
return $form;
}
}
Have in your application.ini something similar to
resources.frontController.actionhelperpaths.Application_Action_Helper = APPLICATION_PATH "/../classes/Application/Action/Helper"
The path should be changed to reflect your file path.

Zend accessing user data in all controllers

Searched and searched for some guidance but cant seem to get anything to work. I wont to access the user data in any index controller to save repetetive code. I have created a ACTION HELPER which calls the Session and returns the users data. Below is how I implemented it all. Calling the helper works but I cant get the data out in any controller.
Application.ini
autoloaderNamespaces[] = "ZC"
Bootstrap.php
protected function _initActionHelpers()
{
Zend_controller_Action_HelperBroker::addHelper(new ZC_Action_Helpers_User());
}
User.php
<?php
Class ZC_Action_Helpers_User extends Zend_Controller_Action_Helper_Abstract
{
public function direct()
{
$storage = new Zend_Auth_Storage_Session();
$data = $storage->read();
$this->_user = $data;
}
}
IndexController.php
<?php
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->_helper->user;
}
I have no problems with the code but say for example how would I get the USERNAME or USERID from the helper???
Thanks for taking the time in looking at this.
J
First, your plugin function have to return the user information and not set it as a class variable:
Class ZC_Action_Helpers_User extends Zend_Controller_Action_Helper_Abstract
{
public function direct()
{
$storage = new Zend_Auth_Storage_Session();
$data = $storage->read();
return $data;
}
}
Then you can use the plugin in any controller you need:
$user = $this->_helper->User->Direct()
You might want to rename some of these functions and classes.
Try to declared in bootstrap path to helpers...
Zend_Controller_Action_HelperBroker::addPath(
APPLICATION_PATH .'/controllers/helpers');
Next use google for this simply question.... howto use helper in ZF

Zend Framework: How to inject a controller property from a Zend_Controller_Plugin

I wrote a plugin that needs to set a property on the controller that's currently being dispatched. For example, if my plugin is:
class Application_Plugin_Foo extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
// Get an instance of the current controller and inject the $foo property
// ???->foo = 'foo';
}
}
I want to be able to do this:
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->foo = $this->foo;
}
}
}
Any help is greatly appreciated!
The action controller is not directly accessible directly from a front-controller plugin. It's the dispatcher that instantiates the controller object and he doesn't appear to save it anywhere accessible.
However, the controller is accessible from any registered action helpers. Since action helpers have a preDispatch hook, you could do your injection there.
So, in library/My/Controller/Helper/Inject.php:
class My_Controller_Helper_Inject extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
$controller = $this->getActionController();
$controller->myParamName = 'My param value';
}
}
Then register an instance of the helper in application/Bootstrap.php:
protected function _initControllerInject()
{
Zend_Controller_Action_HelperBroker::addHelper(
new My_Controller_Helper_Inject()
);
}
And, as always, be sure to include My_ as an autoloader namespace in configs/application.ini:
autoloaderNamespaces[] = "My_"
Then, in the controller, access the value directly as a public member variable:
public function myAction()
{
var_dump($this->myParamName);
}
One thing to note: Since the helper uses the preDispatch() hook, I believe it will get called on every action, even an internal forward().
Browsing through the API, I didn't find a way to reach the controller directly (I'm guessing this loop is performed before the controller exists). What I could find is almost as easy to access, albeit with a bit different syntax.
Via request params
class Application_Plugin_Foo extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$yourParam = 'your value';
if($request->getParam('yourParam')) {
// decide if you want to overwrite it, the following assumes that you do not care
$request->setParam('yourParam', $yourParam);
}
}
}
And in a Zend_Controller_Action::xxxAction():
$this->getParam('yourParam');
Via Zend_Controller_Action_Helper_Abstract
There's another way mentioned in MWOP's blog, but it takes the form of an action helper instead: A Simple Resource Injector for ZF Action Controllers. His example would let you access any variable in Zend_Controller_Action as $this->yourParam.

How to start testing Zend Framework Models?

How do I begin testing my models in a Zend Framework 1.8+ application?
Let's say I have my application set up to start testing. I have already tested a controller, so I know it works. I have all my controllers extending my ControllerTestCase.php file:
<?php
require_once 'Zend/Application.php';
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
public $application;
public function setUp()
{
$this->application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$this->bootstrap = array($this, 'appBootstrap');
parent::setUp();
}
public function appBootstrap()
{
$this->application->bootstrap();
}
public function tearDown()
{
Zend_Controller_Front::getInstance()->resetInstance();
$this->resetRequest();
$this->resetResponse();
$this->request->setPost(array());
$this->request->setQuery(array());
parent::tearDown();
}
}
But now I want to start testing my models. It seems like my ModelTestCase.php would not extend Zend_Test_PHPUnit_ControllerTestCase but rather a Zend_Test_PHPUnit_ModelTestCase, but no such class exists that I know of. How can I start testing my Zend Framework models?
There is a base ControllerTestCase provided for you because there are complex steps needed to setup and tear down the environment for testing a controller. The input is a mock HTTP request, and the output is rendered HTML that you need to scrape to find expected content.
A Model is more like a plain old PHP object. There's less environment to set up. The interface is simply method calls to the object.
So I would start a TestCase class that extends PHPUnit's plain TestCase, and start by adding at least one test method (as an empty function) for each method in your Model class. You will eventually have many test methods for each method in your Model class, but creating the empty test methods is a good way to keep from forgetting some of your Model methods.
Note that a Model is not a Table -- a Model typically uses one or more Table objects. By following this pattern, you have the opportunity to create mock objects for Tables so you can run the test suite without requiring a live connection to a database.
Here's an example of setting up a mock Table object, which is hardcoded to return a synthetic data set instead of a data set from a database.
<?php
class MyModelTest extends PHPUnit_Framework_TestCase
{
protected $_model;
public function setUp()
{
$foo = $this->getMock('FooTable', array('find'));
$foo->expects($this->any())
->method('find')
->will($this->returnValue(array("id"=>"123")));
$this->_model = new MyModel();
$this->_model->setFooTable($foo);
}
public function testCountElements()
{
$this->_model->get(123);
$n = $this->_model->countElements();
$this->assertEquals(1, $n);
}
public function testAsArray()
{
$this->_model->get(123);
$a = $this->_model->asArray();
$this->assertType('array', $a);
}
public function testAddElement()
{
// ...etc.
}
public function testGetElement()
{
// ...etc.
}
}