I need to add a table prefix to zend framework configurations. But it seems really complicated matter adding such a configuration (I have to add too many lines of code to do that). Is there a way to set the table prefix in a simple manner? (like other frameworks do). I'm using Zend Framework 1.11
if you use Zend_Db_Table_Abstract, you could extend this class like this:
class My_Db_Table_Abstract extends Zend_Db_Table_Abstract
{
protected function _setupTableName()
{
parent::_setupTableName();
$prefix = 'StackOverflow'; // maybe from config..
$this->_name = $prefix . '_' . $this->_name;
}
}
class User extends My_Db_Table_Abstract
{
$this->_name = 'user';
}
Related
We are looking at using Slim 3 as the framework for our API. I have searched SO and the Slim docs, but cannot find an answer to the issue. If we have different route files (e.g. v1, v2, etc.) and if two routes have the same signature, an error is thrown. Is there any way to cascade the routes so that the last loaded route for a particular signature is used?
For example, say v1.php has a route for GET ("/test") and v2.php also contains this route, can we use the latest version? Even simpler would be if a file of routes contains two routes with the same signature, is there a way of the latter method being used (and no error being thrown)?
A similar question is asked here but this uses hooks (which have been removed from Slim 3 as per here)
I looked at the Slim code and I didn't find a simple way of allowing duplicated routes (preventing the exception).
The new Slim uses FastRoute as dependency. It calls FastRoute\simpleDispatcher and doesn't offer any configuration possiblity. Even if it did allow some configuration, FastRoute doesn't have any built-in option to allow duplicated routes. A custom implementation of a DataGenerator would be needed.
But following the instructions above, we can get a custom DataGenerator by passing to Slim App a custom Router which instantiates some FastRoute::Dispatcher implementation which then uses the custom DataGenerator.
First the CustomDataGenerator (let's go the easy way and do some copy and pasting from \FastRoute\RegexBasedAbstract and \FastRoute\GroupCountBased)
<?php
class CustomDataGenerator implements \FastRoute\DataGenerator {
/*
* 1. Copy over everything from the RegexBasedAbstract
* 2. Replace abstract methods with implementations from GroupCountBased
* 3. change the addStaticRoute and addVariableRoute
* to the following implementations
*/
private function addStaticRoute($httpMethod, $routeData, $handler) {
$routeStr = $routeData[0];
if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {
foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {
if ($route->matches($routeStr)) {
throw new BadRouteException(sprintf(
'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"',
$routeStr, $route->regex, $httpMethod
));
}
}
}
if (isset($this->staticRoutes[$httpMethod][$routeStr])) {
unset($this->staticRoutes[$httpMethod][$routeStr]);
}
$this->staticRoutes[$httpMethod][$routeStr] = $handler;
}
private function addVariableRoute($httpMethod, $routeData, $handler) {
list($regex, $variables) = $this->buildRegexForRoute($routeData);
if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {
unset($this->methodToRegexToRoutesMap[$httpMethod][$regex]);
}
$this->methodToRegexToRoutesMap[$httpMethod][$regex] = new \FastRoute\Route(
$httpMethod, $handler, $regex, $variables
);
}
}
Then the custom Router
<?php
class CustomRouter extends \Slim\Router {
protected function createDispatcher() {
return $this->dispatcher ?: \FastRoute\simpleDispatcher(function (\FastRoute\RouteCollector $r) {
foreach ($this->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
}, [
'routeParser' => $this->routeParser,
'dataGenerator' => new CustomDataGenerator()
]);
}
}
and finally instantiate the Slim app with the custom router
<?php
$app = new \Slim\App(array(
'router' => new CustomRouter()
));
The code above, if a duplicated route is detected, removes the previous route and stores the new one.
I hope I didn't miss any simpler way of achieving this result.
I am a little confused in this Doctrine model concept , lets say we a table called "article"
Doctrine will generate class called
i am using Zend framework and Doctrine 1.2
models/generated/BaseArticle.php
models/ArticleTable.php
models/Article.php
Is it true to call the ArticleTable in the controller in this way
$tableArticle = Doctrine::getTable('Article');
then to save it in the Article Object like this
$article = new Article();
$fArticles = $tableArticle->getFeaturedArticles();
foreach ($fArticles as $fArticle) {
$article->fromArray($fArticle);
echo $article->title
}
Or I have to let the Article.php to call the ArticleTable ?
then to initiate an Article.php object in the controller ?
class Article extends BaseArticle
{
public function getFArticles()
{
$tableArticle = Doctrine::getTable('Article');
$obj = $tableArticle->getFeaturedArticles();
return $obj;
}
Article.php should not call ArticleTable.php unless really, really needed. In table classes you will only hold queries called by controller like:
$featuredArticles = ArticleTable::getInstance()->getFeatured() ;
Above code is simpler and you will have autocompletion in any IDE.
The reason not to call queries in Article.php is that you will have easier transition to Doctrine2 one day.
For a table call tbl_article or just article, doctrine will generate Article.php and BaseArticle.php. Base classes must not be changed manually.
Article class is where your logic goes. For example, you fetch list of ALL articles in database. When you display them, you want feature articles to have a star (just an example):
controller:
$allArticles = ArticleTable::getInstance()->findAll() ;
template (Smarty version here):
{foreach $allArticles as $article}
{if $article->isFeatured()} <img src=.. some image ..>{/if}
<h5>{$article->title}
{/foreach}
and the model class
class Article extends BaseArticle
{
const STATUS_FEATURED = 1 ;
public function isFeatured()
{
return $this->status == self::STATUS_FEATURED ;
}
}
All these are just some examples, in real life it is much more usefull.
And what are you actually trying to do with this fromArray($fArticle)? I don't see any point of that code.
So i have been designig an application to run on the Zend Framework 1.11 And as any programmer would do when he sees repeated functionalities i wanted to go build a base class with said functionalities.
Now my plan is to build a library 'My' so i made a folder in the library directory in the application. So it looks like this
Project
Application
docs
library
My
public
test
So i created a BaseController class in the My folder and then decided to have the IndexController in my application extend the BaseController.
The Basecontroller looks like this :
class My_BaseController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->test = 'Hallo Wereld!';
}
}
And the IndexController looks like this :
class WMSController extends My_BaseController
{
public function indexAction()
{
parent::indexAction();
}
}
As adviced by a number of resources i tried adding the namespace for the library in the application.ini using the line
autoloadernamespaces.my = “My_”
But when i try to run this application i recieve the following error
Fatal error: Class 'My_BaseController' not found in
C:\wamp\www\ZendTest\application\controllers\IndexController.php
Am i missing something here? Or am i just being a muppet and should try a different approach?
Thanks in advance!
Your original approach will work for you in application.ini, you just had a couple of problems with your set up.
Your application.ini should have this line:-
autoloadernamespaces[] = "My_"
Also, you have to be careful with your class names, taking your base controller as an example, it should be in library/My/Controller/Base.php and should look like this:-
class My_Controller_Base extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->test = 'Hello World!';
}
}
You can then use it like this:-
class WMSController extends My_Controller_Base
{
public function indexAction()
{
parent::indexAction();
}
}
So, you had it almost right, but were missing just a couple of details. It is worth getting to know how autoloading works in Zend Framework and learning to use the class naming conventions
I don't know about .ini configuration, but I add customer libraries like this (index.php):
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()->registerNamespace('My_');
Where do i place the user defined functions in zend framework. These functions will used across the framework in many controls, views or models. Do i need to convert this to a utility class? Or i can just keep it as a set of functions and include it in index.php.
what is the best practice for this?
Typically you would put your functions into a class in the library for the auto loader. Use the naming conventions for ZF to make life easier.
adjust your application.ini to add a namespace.
Examples:
//application.ini
autoloaderNamespaces[] = "My_"
//this would equate to the folder My in the folder library
/application
/library
/My
//any class you built would be named My_Classname and be called in your app by Classname()
<?php
class My_Classname {
public function myFunction() {
}
}
//in your conrtoller for example you might call
public function indexAction() {
$class = new My_Classname();
$class->myFunction();
//or if you declared myFunction() static...
$class = My_Classname::myFunction();
}
Make it by following ZF directory structure:
Make Action Helpers for Controllers and View Helpers for Views :
In your library folder which is set in set_include_path:
create library/My/View/Helper/Common.php
Like below:
class My_View_Helper_Common extends Zend_View_Helper_Abstract
{
public function common()
{
return $this;
}
public function getCity($id)
{
$registry = Zend_Registry::getInstance();
$DB = $registry['DB'];
$result = $DB->fetchPairs("select * from firm_dtl");
return $result;
}
}
OR Call in View:
$this->common()->getCity($id);
Same process fro action helpers:
Make in library/My/Action/Helper/Common.php
Hello I need to use evalmath.class.php within a Yii application. How can I include it from my controller?
Something like this:
public function actionFormulas() {
include('models/evalmath.class.php');
$m = new EvalMath;
...
}
But the above code does not work. How can I include an external class within a controller?
In your example, to use include/require you probably need to add some path info with dirname(__FILE__).'/../models/...' or similar, but to do it within the Yii framework, you would first create an alias (usually in your main config file) with setPathOfAlias :
Yii::setPathOfAlias('evalmath', $evalmath_path);
Then you can use Yii::import like so:
Yii::import('evalmath', true);
and proceed as you were:
$m = new EvalMath();
..etc...
class ServiceController extends Controller
{
public function actionIndex()
{
Yii::import('application.controllers.back.ConsolidateController'); // ConsolidateController is another controller in back controller folder
echo ConsolidateController::test(); // test is action in ConsolidateController