I'm creating an application that exposes a RESTful API in a module called api. For the other modules I created a little class that returns a Zend_Controller_Router_Rewrite object with custom defined routes:
$router = new Zend_Controller_Router_Rewrite();
foreach ($this->_modules as $module) {
if ($module === 'api') continue;
foreach ($this->_getConfigFiles($module) as $filename) {
$config = new Zend_Config_Ini($filename, 'routes');
$router->addConfig($config, 'routes');
}
}
return $router;
For the default module I have the following route:
[routes]
routes.default_index_index.type = Zend_Controller_Router_Route
routes.default_index_index.route = /
routes.default_index_index.defaults.module = default
routes.default_index_index.defaults.controller = index
routes.default_index_index.defaults.action = index
Now, in my Bootstrap file file I have the following:
$router = Shark_Module_Loader::getInstance()->getRouter();
$frontController->setRouter($router);
$frontController->getRouter()->removeDefaultRoutes();
$apiRoute = new Zend_Rest_Route($frontController, array(), array('api'));
$router->addRoute('rest', $apiRoute);
If I skip adding the rest route everything works fine for the default module, of course. But when I add the RESTful route the routes defined in the router are overridden(?), so the current route in the index action of the index controller of the default module ($this->getFrontController()->getRouter()->getCurrentRoute();) is an instance of Zend_Rest_Route. Thus, when trying to access a custom route defined in on of the route config files, lets say:
...
routes.default_pages_view.type = Zend_Controller_Router_Route
routes.default_pages_view.route = /view/:page
routes.default_pages_view.defaults.module = default
routes.default_pages_view.defaults.controller = pages
routes.default_pages_view.defaults.action = view
...
I get a 404 error saying that the request action (get) is not present.
I already went through the docs and didn't see any hint that suggests this behavior.
Any help and guidance will be appreciated.
There is no way to do this out of the box. (Check out this question)
You need to extend the Zend_Controller_Router_Route class. I've done it like this:
class Mauro_Controller_Router_Route_Method extends Zend_Controller_Router_Route {
protected $_method;
public function __construct($route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null) {
list($this->_method, $route) = explode(' ', $route, 2);
parent::__construct($route, $defaults, $reqs, $translator, $locale);
}
public function match($path, $partial = false) {
$requestMethod = $this->getRequest()->getMethod();
$requestMethod = $this->getRequest()->getParam('method')
? strtoupper($this->getRequest()->getParam('method'))
: $requestMethod;
return $requestMethod == strtoupper($this->_method)
? parent::match($path, $partial)
: false;
}
protected function getRequest() {
return Zend_Controller_Front::getInstance()->getRequest();
}
}
You can then use it like this:
$router->addRoute( new Mauro_Controller_Router_Route_Method( 'GET /view/:page', array( 'controller' => 'pages', 'action' => 'view' ), array( 'page' => '/d+', ) ) );
Related
I'm trying to configure routes in my OctoberCMS app. I configure routes in Plugin.php file of my plugin.
At the moment my code:
public function boot()
{
Validator::extend('numeric_for_repeater', function($attribute, $value, $parameters) {
foreach ($value as $v)
{
$validator = Validator::make(
$v,
[
'stock_quantity' => 'sometimes|numeric',
'stock_votes_quantity' => 'sometimes|numeric',
'value' => 'sometimes|numeric',
],
$parameters
);
if ($validator->fails())
return false;
}
return true;
});
\Route::get('/oferty/{id}', function ($id = null) {
$theme = Theme::getActiveTheme();
$path = \Config::get('cms.themesPath', '/themes').'/'.$theme->getDirName();
$this->assetPath = $path;
$offer = new Offer();
return \View::make(self::MAMF_PAGE_DIR . 'oferta.htm', ['offer' => $offer->getOfferById($id)]);
});
}
but I got an error:
View [.var.www.plugins.mamf.mamf2017..........themes.mamf2017.pages.oferta.htm] not found. because by default October expects views files in plugin directory.
How can I render view outside of plugin dir, for ex in themes path like this app/themes/mamf2017/pages/oferta.htm
I guess self::MAMF_PAGE_DIR is full base path your application. for example like
/var/www/vhosts/octdev/themes/responsiv-flat/
In short \View::make need absolute path from root
now it will try to look file with configured extensions for october-cms its .htm. others are .blade and .htm.blade etc ..
so in your case (view)file name is 'oferta.htm' that .(dot) is translated to '/' path separator so just don't use it and just use 'oferta' so it will check all possible values in pages directory
oferta.htm
oferta.blade
oferta.htm.balde
this adding .htm is automatic thing so you just need to provide name of view then it will find and work automatically
\Route::get('/oferty/{id}', function ($id = null) {
$theme = \Cms\Classes\Theme::getActiveTheme();
$path = \Config::get('cms.themesPath', '/themes').'/'.$theme->getDirName();
$this->assetPath = $path;
$offer = new Offer();
return \View::make(base_path() . $path . '/pages/' . 'oferta', ['offer' => $offer->getOfferById($id)]);
});
this is tested and working fine hope this will help you.
if its not working please comment.
i have a page in my website (zendframework 1) that parses the GET parameter and query its data from the database to show it to the user.
-> my current url : https://example.com/index.php/product/info?id=123
i want my url to be more human readable
-> https://example.com/index.php/product/iphone-7s-white
so basicaly i want to parse the GET parameter in the url and query the name of the product from the database in order to make it appear as the page name in the url.
i came across some solutions, one of them is achieved by looping through the database (in bootstrap.php) and adding a route for each product, but this seems like a mess, (products can reach 200k or maybe more than that).
is there a better solution for my problem ? thanks in advance
So basically, ZF1 provides a default route that leads to the controller/action of the names from the url.
You can add custom routes from the application/Bootstrap.php file by adding a function there:
/**
* This method loads URL routes defined in /application/configs/routes.ini
* #return Zend_Router
*/
protected function _initRouter() {
$this->bootstrap('frontController');
$front = $this->getResource('frontController');
$router = $front->getRouter();
$router->addRoute(
'user',
new Zend_Controller_Router_Route('product/:slug', array(
'controller' => 'product',
'action' => 'details',
), array(
'slug' => '[A-Za-z0-9-]+',
))
);
return $router;
}
And here you go!
As described by Chris, you need to change your controller code to handle the request. Another solution would be to use an extra action.
final class ProductController
{
public function infoAction()
{
$product = $table->find($this->_param('id'));
$this->view->product = $product;
}
public function detailsAction()
{
$product = $table->fetch(['slug' => $this->_param('slug')]);
$this->view->product = $product;
$this->render('info');
}
}
Now, assuming you do a lot of processing in infoAction, you could go with a forward:
final class ProductController
{
public function infoAction()
{
$product = $table->find($this->_param('id'));
$this->view->product = $product;
}
public function detailsAction()
{
$product = $table->fetch(['slug' => $this->_param('slug')]);
$this->forward('info', 'product', [
'id' => $product->id,
]);
}
}
It is less efficient (2 requests instead of one), but allows you to reuse your code.
in my laravel 4.2 projects I use the file ioc.php, to use functions anywhere in my application:
Laravel 4.2 structure
|
|
|app|
|routes.php
|ioc.php <-- place here
My ioc.php content:
<?php
// services class
App::singleton('ApiRpService', function()
{
$config = Config::get('app.web_config.api');
$config['lang'] = Config::get('app.locale');
$config['currency'] = Config::get('app.currency');
$service = new \services\ApiService();
$service -> configure(array_merge($config,Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]));
return $service;
});
App::singleton('CartService', function()
{
//die(Config::get('app.web_config.webs.mantaspersonalizadas.es.local'));
$service = new \services\CartService(App::make('ApiRpService'));
return $service;
});
App::singleton('ApiCcService',function(){
$api_cc = new \services\ApiCcService(Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['secret_key_old_cc']);
return $api_cc;
});
// shared cart when head render
View::composer('layouts.header', function($view)
{
$cart_service = App::make('CartService');
$params = array();
$params['cart'] = $cart_service->getCart();
//Controller::call('PagesController#getPromotionData');
App::make('PagesController')->getPromotionData();
# lenguajes extras
$params['extra_langs'] = [];
$extra_langs = array_merge(#Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['lng_extra'],array(#Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['lng_default']));
if (count($extra_langs) > 0){
foreach($extra_langs as $lang)
{
if ($lang != App::getLocale())
{
$route_name = substr(Route::currentRouteName(), 0, strrpos(Route::currentRouteName(),'_')).'_'.$lang;
//die(URL::route($route_name));
$params['extra_langs'][] = array(
'lang' => $lang,
'url' => URL::route($route_name,array('--',Input::get('id','')))
);
}
}
}
$params['web_url'] = Request::root() . (strlen(Request::segment(1)) == 2? '/'.Request::segment(1):'');
//dd($params['promotion_data']);
$view -> with($params);
});
View::composer('layouts.head', function($view)
{
if (App::environment('production'))
$view -> with('g_analytics_id', #Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['g_analytics']['account']);
});
View::composer('layouts.metas', function($view)
{
$params = [];
if (Lang::has('messages.welcome'))
$params['title'] ="";
if (Lang::has('messages.welcome'))
$params['description'] ="";
$view -> with($params);
});
// shared newsletter when footer render
View::composer('layouts.footer', function($view)
{
$api = App::make('ApiRpService');
$view -> with(array(
'token' => $api->getPublicToken(),
'google_plus' => #Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['google_plus'],
'facebook' => #Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['facebook'],
'twitter' => #Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['twitter'],
'chat_online' => #Config::get('app.web_config.webs')[$_SERVER['SERVER_NAME']]['chat_online']
));
});
App::singleton('imghelper', function(){
return new \utils\ImageHelper(Config::get('app.web_config.urlStaticProductsImg'));
});
In Laravel 5 docs not mention the ioc.php...
Where I can place these functions?
Note that these functions are used in all views.
Generally, your individual services should have their own ServiceProvder. These can be placed in any particular directory, and you can register all your service providers in your config/app.php to be automatically loaded and run.
You'll see in your config/app.php that a base Laravel project pre-registers some providers for your commonly used facades like DB.
Just make sure that the names of your service providers follow the PSR-4 standard so that Laravel's auto-loader can correctly resolve the class!
If you're looking for the docs on "IOC" in Laravel 5, it is now called the "Service Container" - here are the docs.
There are given article URLs in a database (e.g. "article1", "article2", "article3").
When I type www.example.com/article1 I want to route to
controller: index,
action:index.
My route is:
//Bootstrap.php
public function _initRoute(){
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$router->addRoute('index',
new Zend_Controller_Router_Route('article1', array(
'controller' => 'index',
'action' => 'index'
))
);
}
But when I click on another link (functional before), I get www.example.com/article1 again.
Is there any way to do this route generally for all URLs in database? Something like:
$router->addRoute('index',
new Zend_Controller_Router_Route(':article', array(
'controller' => 'index',
'action' => 'index'
))
);
I usually set up an ini file instead of going the xml route or "new Zend_controller_Router_Route" way. In my opinion its a little easier to organize. This is how I do what you are looking for. I recommend that make some changes to your routing and not use a route of http://domain.com/article1 but more like http://domain.com/article/1. either way here is what I would do in your situation.
In your routes.ini file
routes.routename.route = "route"
routes.routename.defaults.module = en
routes.routename.defaults.controller = index
routes.routename.defaults.action = route-name
routes.routename.defaults.addlparam = "whatevs"
routes.routename.route = "route2"
routes.routename.defaults.module = en
routes.routename.defaults.controller = index
routes.routename.defaults.action = route-name
routes.routename.defaults.addlparam = "whatevs2"
routes.route-with-key.route = "route/:key"
routes.route-with-key.defaults.module = en
routes.route-with-key.defaults.controller = index
routes.route-with-key.defaults.action = route-with-key
In your bootstrap file
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
#... other init things go here ...
protected function _initRoutes() {
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/routes.ini');
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$router->addConfig($config,'routes');
$front->setRouter($router);
return $router;
}
}
In your controller you can then do this
class IndexController extends Zend_Controller_Action {
public function routeNameAction () {
// do your code here.
$key = $this->_getParam('addlparam');
}
public function routeWithKeyAction () {
$key = $this->_getParam('key');
// do your code here.
}
}
I'm wondering if anyone can help me with the next issue I have.
I want to be able to setup my project with multilanguage support with and without Uri lang flag, and also, with module structure.
I mean something like
http://mydomain/
http://mydomain/forum
http://mydomain/gallery
Navigate without lang uri parameter with the Zend_Locale + Zend_Translate default (en)
And also :
http://mydomain/es
http://mydomain/es/forum
http://mydomain/es/gallery
I've followed some tutos that I've found, but I still can't do so.
This is my current code :
I have zend _initRoute, _initLocale and _initTranslate setted on my bootstrap.php as follow:
protected function _initRoutes()
{
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$module = new Zend_Controller_Router_Route_Module(
array(),
$front->getDispatcher(),
$front->getRequest()
);
$language = new Zend_Controller_Router_Route(
':lang',
array(
'lang' => 'es'
)
);
/**
* I didn't chain this route cause doesn't work as I expected,
* but this is how I want to be able to navigate.
*
**/
$default = new Zend_Controller_Router_Route(
':controller/:action/*',
array(
'lang' => 'es',
'module' => 'default',
'controller' => 'index',
'action' => 'index'
)
);
$chainRoute = new Zend_Controller_Router_Route_Chain();
$chainRoute->chain($language)
->chain($module);
$router->addRoute('default', $chainRoute);
return $router;
}
/**
*
* Default locale: es_AR
*/
protected function _initLocale()
{
$local = new Zend_Locale();
$local->setDefault('es_AR');
Zend_Registry::set('Zend_Locale', $local);
}
/**
*
* Inisializacion de los lenguages y el Locale por default
*/
protected function _initTranslate()
{
$translate = new Zend_Translate(
'Array',
APPLICATION_PATH . "/langs/",
null,
array(
'scan' => Zend_Translate::LOCALE_DIRECTORY
)
);
Zend_Registry::set('Zend_Translate', $translate);
$translate->setLocale(Zend_Registry::get('Zend_Locale'));
}
I also register the next Language Plugin :
class MyApp_Controller_Plugin_Language extends Zend_Controller_Plugin_Abstract
{
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$lang = $request->getParam('lang', null);
$locale = Zend_Registry::get('Zend_Locale');
$translate = Zend_Registry::get('Zend_Translate');
if ($translate->isAvailable($lang)) {
$translate->setLocale($lang);
$locale->setLocale($lang);
} else {
//throw new Zend_Controler_Router_Exception('Translation language is not available', 404);
$lang = $locale->getLanguage();
$locale->setLocale($lang);
$translate->setLocale($lang);
}
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$router->setParam('lang', $lang);
}
}
Also I've created my own Url helper extended by zend url helper which uses the 'Language_Action_Helper':
class Zend_View_Helper_MyUrl extends Zend_View_Helper_Url
{
protected function _getCurrentLanguage()
{
return Zend_Controller_Action_HelperBroker::getStaticHelper('Language')
->getCurrent();
}
public function myUrl($urlOptions = array(), $name = null, $reset = true, $encode = true)
{
$urlOptions = array_merge(
array(
"lang" => $this->_getCurrentLanguage()
),
$urlOptions
);
return parent::url($urlOptions, $name, $reset, $encode);
}
}
And then I've created an Anchor helper which uses my url Helper :
class Zend_View_Helper_Anchor extends Zend_View_Helper_Abstract
{
public function anchor
(
$anchorText,
$controller,
$action,
Array $params = array()
)
{
$front = Zend_Controller_Front::getInstance();
$defaultUrl = array(
'module' => $front->getRequest()->getModuleName(),
'controller' => $controller,
'action' => $action
);
if (!empty($params)) {
foreach ($params as $param => $value) {
$defaultUrl[$param] = $value;
}
}
// using my url helper
$url = $this->view->myUrl(
$defaultUrl,
null,
true
);
$anchor =<<<HTML
{$anchorText}
HTML;
return $anchor;
}
}
This is the Language Action helper to provide the language inside the controller used by my url helper.
class Controller_Helper_Language extends Zend_Controller_Action_Helper_Abstract
{
/**
*
* Get Current language
*
* #return mixed string|null
*/
public function getCurrent(){
if (!Zend_Registry::isRegistered("Zend_Locale"))
return null;
return Zend_Registry::get("Zend_Locale")->getLanguage();
}
/**
*
* Get translator
*
* #return mixed Zend_Translate|null
*
*/
public function getTranslator(){
if (!Zend_Registry::isRegistered("Zend_Translate"))
return null;
return Zend_Registry::get("Zend_Translate");
}
}
My final approach is with this structure, be able to set up standard routes like :
http://mydomain/forum/:id
http://mydomain/topic/:id
http://mydomain/section/:id
http://mydomain/user/:user
with language support.
How these routes must be configured to meet my needs?, I mean, I've tried to do something like :
// what may I do here? How do I chain this route with my language router
$topicRoute = new Zend_Controller_Router_Route(
'topic/:id',
array(
'module' => 'default',
'controller' => 'forum',
'action' => 'topic',
'id' => ':id'
),
array(
'id' => '^[0-9]$'
)
)
Also this router config bring me some problems with my navigation config.
When I set this router, and then navigate to /topic/id, when I hover any link given by the navigation.xml, always return the same URI given by this config.
http://mydomain/topic/id
Is anyone familiar with this?, Is this possible to do? Is any different way to do something like this? I've tried some different things which make me closer to my goal, but this is the most closer I could...
Thanks.
A better and cleaner way is to zend routes with hostname (eg. sub domains) take a look at following
http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.hostname
this method is more easy and SEO friendly too.