Respect/Rest uri part corresponds to controller name - php

i'm trying to implement Respect/Rest in my existing CMS.
The Problem:
I would like to create a single magic route to works like: /admin/*/save, calls the * controller...
I would like to make something like this:
$r->any('/admin/*/save/*/', function($controller, $id = null) use ($r) {
return $r->dispatchClass($controller,array($id));
});
Note that i don't know which HTTP method user is using.
Actually I "solved" this problem with something like:
$r->any('/admin/*/save/*/', function($controller, $id = null) use ($tcn) {
$r = new Router;
$r->any('/admin/*/save/*/', $tcn($controller . '_save'), array($id));
return $r->run();
});
$tcn is a named function that returns the full namespace of the controller.
I know it's not a good approach.
EDIT:
This project wants to be Open Source, but it's still being created.
We're trying to transport an old project made on functional paradigm to OOP.
We are trying to learn about OOP while making an useful project.
Actuall state of the files can be found at: https://github.com/dindigital/skeleton
Alganet: The bootstrap for admin routes can be found at: https://github.com/dindigital/skeleton/blob/master/admin_routes.php
A simple controller sample: https://github.com/dindigital/skeleton/blob/master/src/app/admin/controllers/TagController.php
https://github.com/dindigital/skeleton/blob/master/src/app/admin/controllers/TagSaveController.php
I liked the Forwards and also the Factory approach... I could not decide yet.

Tricky question! That depends a lot of why are you making these routes dynamic. Can you show us some sample structure for your controllers so I can improve the answer?
Meanwhile, two native features that can help:
Forwards
You can treat the problem as an internal forward (does not make redirects). It's normally to redirect to other static routes, but you can redirect to a new one as well:
$r->any(
'/admin/*/save/*/',
function ($controller, $id) use ($tcn, $r) {
return $r->any(
"/admin/$controller/save",
$tcn($controller . '_save'),
array($id)
);
}
);
Factory Routes
Also, Respect\Rest implements factory routes. It is experimental but stable in tests:
$r->factoryRoute(
'ANY',
'/admin/*/save/*/',
'MyAbstractController',
function ($method, array $params) use ($tcn) {
return new $tcn($params[0] . '_save');
}
);

Related

Opencart: call method from another controller

I need to call in checkout/confirm.tpl file a custom function that i've made in controller/product.php
what's the best way to make this?
i've tried this, but doesn't work:
$productController = $this->load->model('product/product');
$productController->customFunction();
yes i find the right answer finally!!! sorry for last bad answer
class ControllerCommonHome extends Controller {
public function index() {
return $this->load->controller('product/ready');
}
}
MVC
in an MVC architecture, a template serves solely for rendering/displaying data; it shouldn't (*) call controller/model functions nor it shouldn't execute SQL queries as I have seen in many third-party modules (and even in answers here at SO).
$productController = $this->load->model('product/product');
nifty eye has to discover that you are trying to load a model into a variable named by controller and you are also trying to use it in such way. Well, for your purpose there would have to be a method controller() in class Loader - which is not (luckily)
How it should be done?
sure there is a way how to access or call controller functions from within templates. In MVC a callable function that is invoked by routing is called action. Using this sentence I can now say that you can invoke an action (controller function) by accessing certain URL.
So let's say your controller is CatalogProductController and the method you want to invoke is custom() - in this case accessing this URL
http://yourstore.com/index.php?route=catalog/product/custom
you will make sure that the custom() method of CatalogProductController is invoked/accessed.
You can access such URL in many ways - as a cURL request, as a link's href or via AJAX request, to name some. In a PHP scope even file_get_contents() or similar approach will work.
(*) By shouldn't I mean that it is (unfortunately) possible in OpenCart but such abuse is against MVC architecture.
$this->load->controller('sale/box',$yourData);
To call ShipmentDate() function of box Controller
$this->load->controller('sale/box/ShipmentDate',$yourData);
May be something like this could help you (or anyone who's interested)
// Load seo pro
require_once(DIR_CATALOG."/controller/common/seo_pro.php"); // load file
$seoPro = new ControllerCommonSeoPro($this->registry); // pass registry to constructor
$url = HTTP_CATALOG . $seoPro->rewrite(
$this->url('information/information&information_id=' . $result['information_id'])
);
return $this->load->controller('error/not_found');
in laravel its so simple just write Controller::call('ApplesController#getSomething');
but there i cant made better than this
$config = new Config();
// Response
$response = new Response();
$response->addHeader('Content-Type: text/html; charset=utf-8');
$response->setCompression($config->get('config_compression'));
$this->registry->set('response', $response);
$action = new Action('product/ready');
$controller = new Front($this->registry);
$controller->addPreAction(new Action('common/maintenance'));
$controller->addPreAction(new Action('common/seo_url'));
$controller->dispatch($action, new Action('error/not_found'));
$response->output();
in this case its well call product/ready

How to create optional REST parameter in Laravel

I'd like my API to handle calls of the such:
/teams/colors
/teams/1/colors
The first would return all colors of all teams, the second would return colors of team 1 only.
How would I write a route rule for this in Laravel?
This should be simple using a laravel route.
Route::pattern('teamid', '[0-9]+');
Route::get('/teams/{teamid}/colors', 'controller#method');
Route::get('/teams/colors', 'controller#method');
Using the pattern, it lets you specify that a route variable must match a specific pattern. This would be possible without the pattern also.
I noticed you mentioned REST in the title. Note that my response is not using Laravel's restful routes system, but its normal routes system, but I'm sure this could be adapted to be restul, or work with the restful system.
Hope this helps.
Edit:
After a bit of looking around, you may be able to use this if you are using Route::resource or Route::controller.
Route::resource('teams', 'TeamsController');
Route::any('teams/{teamid}/colors', 'TeamsController#Method');
// Or to use a different route for post, get and so on.
Route::get('teams/{teamid}/colors', 'TeamsController#getMethod');
Route::post('teams/{teamid}/colors', 'TeamsController#postMethod');
Note: the resource word above can be replaced with ::controller.
*Note 2: I have not tested this and am unable to guarantee it would work, but it does seem possible.*
You may try something like this:
class TeamsController extends BaseController {
// GET : http://example.com/teams
public function getIndex()
{
dd('Colors of all teams');
}
// GET : http://example.com/teams/1/colors
public function getColorsById($id)
{
dd("Colors of team $id");
}
// This method will call the "getColorsById" method
public function missingMethod($parameter = array())
{
if(count($parameter) == 2) {
return call_user_func_array(array($this, 'getColorsById'), $parameter);
}
// You may throw not found exception
}
}
Declare a single route for both methods:
Route::controller('/teams', 'TeamsController');

List of Kohana controllers

I'm looking for a way to programatically get a list of controllers in a Kohana application.
Something like:
public function build_site_map(){
$controllers = Kohana::get_controllers();
echo '<ul>';
foreach($controllers as $controller){
echo '<li>'.$controller.'</li>';
}
echo '</ul>';
}
I realize I could read the /application/classes/controllers/ directory, but I'm hoping there's an easier way.
Thanks,
Getting a list of your controller files could be done with Kohana::list_files('classes/controller'). But as Michal already said, there isn't a 1:1 realtionships between controllers/actions and routes.
I'm afraid there is no Kohana::get_controllers() method that you can easily call to get a a sitemap of sorts. This is because controllers are called dynamically, i.e. based on the request's URL and Routes configuration Kohana's checking whether a controller (and action) exist and then call them. Kohana does not keep record of all available controllers and actions that can be accessible.
Neither traversing the /application/classes/controllers directory and getting the list of all files would give you the desired result, because there are not only actions to be read (which can be fairly easily done with Reflection class), but there are also Routes which you have to take into account.
As you can see this is potentially very complex issue and one that cannot be simply answered with a snippet of code that can be pasted here.
If you decide to write a script that would actually create such a map, but you stumble into a problem on the way, we would be able to more helpful then otherwise this question is too open. Also, if you were to write it, I suggest you create it as a module that you would be able to include in any other projects and share it.
Here my solution to get all the controllers and their actions. I use it to add permissions into our system https://github.com/open-classifieds/openclassifieds2/
/**
* get all the controllers and the actions that can be used
* #return array
*/
public static function list_controllers()
{
$list_controllers = array();
$controllers = Kohana::list_files('classes/controller');
foreach ($controllers as $controller)
{
$controller = basename($controller,'.php');
$list_controllers[] = $controller;
$class = new ReflectionClass('Controller_Panel_'.$controller);
$methods = $class->getMethods();
foreach ($methods as $obj => $val)
{
if (strpos( $val->name , 'action_') !== FALSE )
{
$list_controllers[$controller][] = str_replace('action_', '', $val->name);
}
}
}
return $list_controllers;
}

Embedding CakePHP in existing page

I've volunteered to create some db app, and I told those guys that it will be very easy, since I wanted to use CakePHP. Sadly after some time they told me they want it inside their already existing web, which is ancient highly customized PHPNuke.
So what I want is to generate just content of one <div> inside an already existing page with CakePHP. I looked up on the internet, but I didn't find what I was looking for. I'm rather a user of the framework, not developer, so I don't know much about the backend and how MVC frameworks are working inside (and this is my first try with CakePHP, since I'm Rails guy).
What I did so far is disabling mod_rewrite for Cake. Inside PHPNuke module I included Cake's index.php and rendering views with an empty layout. This somehow works, but the thing is how to form URLs. I got it working by now with
http://localhost/modules.php/posts?op=modload&name=xxxxx&file=index&do=xxxxx
but with this all links to CSS and images on PHPNuke site are broken.
Is there any way to use something like
http://localhost/modules.php?op=modload&name=xxxxx&file=index&do=xxxxx&CakePHP=/posts/bla/bla
or any other way that could do the job? I really don't want to change anything in existing PHPNuke app.
Thank you very much
Well, if you don't understand how CakePHP works you'll have trouble doing what you want, since it would mean putting hacks into the CakePHP core files to bypass the default routing. This basically means that you would be re-working the way CakePHP works, so you can forget about ever updating to a newer CakePHP version, and maintenance would be hell.
If you want to modify the system, but keep PHP-Nuke, I'd advise against jamming CakePHP in there, since that would open up too many problems to be able to predict beforehand.
I think your options are as follows:
Learn how PHP-Nuke works so you can modify it
Use regular php for the pages
Either of those are easier by orders of magnitude compared to what you wanted to do.
So to sum up solution I found, if someone will be looking for something similar. Problem solved by using two custom route classes ( http://manual.cakephp.neoboots.com/2.0/en/development/routing.html#custom-route-classes )
class CustomParserRoute extends CakeRoute {
function parse($url) {
if (parent::parse($url) != false) //if default parser has the match continue
{
// call to Router class to do the routing for new url string again,
// if &cakePHP= is in query string, use this, or use default
if ($_GET['cakePHP']) {
$params = Router::parse($_GET['cakePHP']);
} else {
$params = Router::parse("/my_controller");
}
return $params;
}
return false;
}
}
class CustomMatcherRoute extends CakeRoute {
// cusotm mathc function, that generates url string.
// If this route matches the url array, url string is generated
// with usual way and in the end added to url query used by PHPNuke
function match($url) {
$result_url = parent::match($url);
if($result_url!= false) {
$newurl = function_to_generate_custom_query()."&cakePHP=".$result_url;
return $newurl;
} else {
return $result_url;
}
}
}
And then simple configuration in routes php
App::import('Lib', 'CustomParserRoute');
App::import('Lib', 'CustomMatcherRoute');
// entry point to custom routing, if route starts with modules.php it matches
// the url and CustomParserRoute::parse class is called
// and route from query string is processed
Router::connect('/modules.php', array('controller' => 'my_controller'), array('routeClass' => 'CustomParserRoute'));
// actual routes used by cakephp app, usual routes that need to use
// CustomMatcherRoute classe, so when new url is generated, it is modified
// to be handled later by route defined above.
Router::connect('/my_controller/:action/*', array('controller' => 'my_controller'), array('routeClass' => 'CustomMatcherRoute'));

Zend Framework Action Stack Alternative

is there a way in Zend to call one controller from another?
I have seen the action stack but that does not seem to work for me and i have read that alot of people think it to be EVIL!
What i am trying to acchive is as follows:
Reports Controller scans through all the modules in the system, it then checks to see if a route has been registered for that module called MODULENAME-reports-run
The controller then reuns that registered route to generate all the reports from all the modules.
The idea is that i can create modules for my application that clients can simple drag and drop into place and the system picks up on the reports.
Your controller should not do any of these things. Your controller should only accept any input from the User Interface and then decide to delegate this to the appropriate classes in your Model.
If you have a ReportController, have it accept any input and forward it to a ReportsService or something else in the Model responsible for generating Reports. It's not the controllers responsibility to generate them.
It should look something like this:
public function generateReportAction()
{
try {
$service = new Model_ReportService;
$service->setReportToGenerate($this->getRequest()->getParam('reportId'));
$this->view->report = $service->generateReport();
} catch (ReportException $e) {
// do something with $e
}
}
If your ReportService needs to generate multiple reports, change the ReportService so it knows how to do that. You could do something like
$service = new Model_ReportService;
$service->setModulesDirectory('something');
$this->view->reports = $service->generateReportsForModules();
Personally I dont think a ReportService should need to know about a Module Directory, so you will want to give the public interface of that Service some more thought. But in general, this is the way to go.
Whatever you do, dont do it in the controller. Controllers ought to be slim.

Categories