I'm reading opencart php source code, and I can't figure this out.
Please take a look at function rewrite() at "$url = $rewrite->rewrite($url);"
<?php
class Url {
private $url;
private $rewrite = array();
public function link($route, $args = '', $connection = 'NONSSL') {
....
foreach ($this->rewrite as $rewrite) {
$url = $rewrite->rewrite($url);
}
return $url;
}
public function addRewrite($rewrite) {
$this->rewrite[] = $rewrite;
}
}
?>
Why above code doesn't generate error ?
The rewrite function is not defined in class Url, and class Url doesn't extend anybody ??
But then I track deeper, it seems that function rewrite is at seo_url class.
class ControllerCommonSeoUrl extends Controller {
// Add rewrite to url class
if ($this->config->get('config_seo_url')) {
$this->url->addRewrite($this);
}
...
public function rewrite($link) {
if ($this->config->get('config_seo_url')) {
$url_data = parse_url(str_replace('&', '&', $link));
....
Why ? I don't see any connection between 'Url' and this 'ControllerCommonSeoUrl' yet. Am I missing some concept here ? What I should do to understand these codes ? Need little guidance here.
foreach ($this->rewrite as $rewrite) {
Iterates over whatever values in:
private $rewrite = array();
And maybe that Url->rewrite array contains an instance of ControllerCommonSeoUrl, that would explain why $rewrite->rewrite() calls ControllerCommonSeoUrl->rewrite().
Also, you'd do yourself a favor by trying to learn to use a debugger :)
check if the controller is loading any model in the script if so , the model method can be simply accessed inside the script which might be the case with your script as $this->rewrite.
The Url class is a generic class that can have multiple URL rewrite method's called, making it possible for people to change the URL rewriting code. Triggering the SEO URL code to add it to the Url class is done in the index.php file by the following
// SEO URL's
$controller->addPreAction(new Action('common/seo_url'));
When that Action is executed, the ControllerCommonSeoUrl executed the index() method, and as with the code you provided, it checks if SEO URL's are active in the settings. If they are, then the current class is added to the array of rewrite's in the Url class. Then whenever someone calls $this->url->link() each of the rewrite classes have their rewrite() method called and the subsequent URL is passed back
Related
I'm creating my own framework. It works like this
localhost/controller/action/firstVariable/second/third (And so on...)
My bootstrap look like this:
$request = Util::getInput('request');
$requestList = explode("/",$request);
$modelName = #ucwords($requestList[0]);
$action = #$requestList[1];
$parameters = array_slice($requestList,2);
$controllerName = $modelName.'s'.'Controller';
I'm getting parameters from an url and save them in a variable $parameters. I would like to send them to the current action in my controller the way Laravel 5 is doing.
Example, in Laravel I specify parameters in the url and thats it.
To call them, I need to do a simple step. Just define them:
public function firstAction($first,$second){
}
When I go to an url like:
localhost/Main/firstAction/first/second/
Function of action 'firstAction' will catch those 2 parameters and then basically I can call them inside of the controller and send it to view.
My extends Controller class:
class Controller{
public function __construct($model,$action){
$modelClass = new main();
$reflection = new ReflectionClass($model.'sController');
$reflection->hasMethod($action) ? $this->$action() : die ('Base Controller call error: Method '. $action .' does not exist in Controller '. $model.'sController');
}
public static function renderView($action,$model,$data){
$model = str_replace('sController','',$model);
//include '../application/views/'.$model.'/'.$action.'.php';
$loader = new Twig_Loader_Filesystem('../application/views/'.$model);
$twig = new Twig_Environment($loader);
echo $twig->render($action.'.php', $data);
}
}
class MainsController extends Controller {
private $_data = array();
public function __construct($model,$action){
parent::__construct($model,$action);
}
public function firstAction($first,$second){
echo 'Hoi';
}
}
How can I do it, the good way? I can of course send the variable $parameter to MainController and than call
$this->_data inside of my action but It is not efficient.
I think I need to use arrays to do it, but I have no idea how.
Thank you.
Check out http://php.net/manual/en/function.call-user-func-array.php
P.S.
You do not have to use reflection in order to check if method on that object's instance exist. Single function call can be enough. Check out http://php.net/manual/en/function.is-callable.php
It would be nice if you would use more descriptive names. Now they are confusing.
I try to pass a parameter to my controller functions from my views but I always get "Page Not Found".
I've been looking for any solutions possible for my problem from here, here, and here but I still couldn't find working solutions and I still don't know what could be the problem. I think I've set everything right, but it's not working. Please tell me if there's something I'm doing wrong.
Here is my controller: Controll.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Controll extends CI_Controller{
public function about($thing){
$case = "About Us";
$data['page'] = $case;
$data['p'] = $thing;
print($thing);
//$this->load->view('/header/header',$data);
$this->load->view('about_us',$data);
$this->load->view('/footer/footer');
}
public function mountain_destination($thing){
$data['page'] = "Mountain Destination";
$data['p'] = $thing;
//$this->load->view('/header/header',$data);
$this->load->view('mountain_destination',$data);
$this->load->view('/footer/footer');
}
}
?>
Here's my routes setting:
$route['(:any)'] = "controll/$1";
$route['default_controller'] = "controll";
$route['404_override'] = '';
And here's one of my script called by onClick that tries to call that controller function:
function goTab(thing,tab){
switch(thing){
case "about":
$body.load("<?php echo site_url('about'); ?>/"+$(tab).text().toLowerCase().replace(/ /g,''));
break;
case "mountain":
$body.load("<?php echo site_url('mountain_destination'); ?>/"+$(tab).text().toLowerCase().replace(/ /g,''));
break;
}
My script runs well and it produces right url. For example, I put parameter "myteam" into "goTab" function, it produces link like this:
"http://127.0.0.1/about/myteam". This link's supposed to call "about" function inside my controller and pass "myteam" as parameter. But instead it returns "Page Not Found". And when I try to call "about" function without any parameters like this: "http://127.0.0.1/about", I get missing argument error like this:
Severity: Warning
Message: Missing argument 1 for Controll::about()
Filename: controllers/Controll.php
Line Number: 22
Please help me.
Thanks in advance.
You're not passing it to your about method. You're looking for a method called myteam within your Controll controller.
Amend your Routes to this;
$route['about/(:any)'] = 'controll/about/$1';
$route['mountain_destination/(:any)'] = 'controll/mountain_destination/$1';
Hope this helps.
This answer of mine might also help you;
Codeigniter Menu from Database
You can create a variable and pass it within constructor and simply use that whenever you need as
class Controll extends CI_Controller {
private $thing;
public function __construct() {
parent::__construct();
$this->thing = $this->uri->segment(3);
}
public function about() {
$data['p'] = $this->thing;
echo $this->thing;
}
public function mountain_destination($thing) {
$data['p'] = $this->thing;
echo $this->thing;
}
}
Where should I put the function that loads a model and Display a view but that is not accessible from the URL. I mean, I need to write a function that should call from the view and this function displays a menu list.
function displayMenu () {
$menu = $this->model->getMenuResults();
$this->load->view( 'ViewResults', $menu);
}
Should I write this as a private function in the main controller?
You can use private functions in codeigniter controller
private function _displayMenu()
{
$menu = $this->model->getMenuResults();
$this->load->view( 'ViewResults', $menu);
}
Straight from documentation
Private Functions
In some cases you may want certain functions hidden from public access. To make a function private, simply add an underscore as the name prefix and it will not be served via a URL request. For example, if you were to have a function like this:
private function _utility()
{
// some code
}
Trying to access it via the URL, like this, will not work:
example.com/index.php/blog/_utility/
For more details go to http://ellislab.com/codeigniter/user-guide/general/controllers.html#private
Put it in one of your helper functions like this
function displayMenu () {
$CI = &get_instance();
//choose whichever is appropriate
//option 1
//if your model is globally loaded then simply call the model like this
//$menu = $CI->loadedmodel->getMenuResults();
// option 2 otherwise load the model here
//$CI->load->model('model_name');
//$menu = $CI->model_name->getMenuResults();
$CI->load->view( 'ViewResults', $menu);
}
Basically everything works if I hard code the URL in my Ajax_Controller, but I want it to access the URL from the CMS field I created.
Thanks in advance. (please ignore when I don't close my braces - just trying to copy / paste efficiently)
In /mysite/_config.php I created a custom config:
Object::add_extension('SiteConfig', 'CustomSiteConfig');
In /mysite/code/CustomSiteConfig.php I added a field where I'll store a URL:
class CustomSiteConfig extends DataObjectDecorator {
function extraStatics() {
return array(
'db' => array(
'COJsonPath' => 'Text'
)
);
}
public function updateCMSFields(FieldSet &$fields) {
$fields->addFieldToTab("Root.CO", new TextField("COJsonPath", "CO JSON URL"));
}
public function getCOJsonPath(){
return $SiteConfig.COJsonPath;
}
This successfully creates a tab in the main parent in the CMS called "CO" and a field named "CO JSON URL". I logged into my CMS and saved http://api.localhost/mymethod/ to that field.
Now I have created an Ajax page type to facilitate running Ajax commands without letting the web site user find where my APIs are, and because jQuery Ajax no likey XSS (cross site scripting).
In /mysite/code/Ajax.php:
class Ajax extends Page {
static $db = array(
);
static $has_one = array(
);
function getCMSFields()
{
$fields = parent::getCMSFields();
return $fields;
}
}
class Ajax_Controller extends Page_Controller {
public function getCO()
{
$buffer = self::createHttpRequest("http://api.localhost/mymethod/");
//$buffer = self::createHttpRequest($CustomSiteConfig::getCOJsonPath());
return $buffer;
}
This code works, but when I try to execute my createHttpRequest() with the line you see commented out, it fails. I know my syntax is wrong, I just can't figure out what it should be. Thanks for helping - I've done this before I just can't figure it out - its Friday.
I spotted several syntax errors in your code:
public function getCOJsonPath(){
return $SiteConfig.COJsonPath;
}
should be:
public function getCOJsonPath(){
return $this->owner->COJsonPath;
}
1) $SiteConfig is never defined at that point.
2) usually you would use $this, but in your case you are inside a DataObjectDecorator, so you have to use $this->owner
3) you can not use . to access properties of an object, in php you have to use ->
moving on to class Ajax_Controller, inside getCO there are the following errors:
1) $CustomSiteConfig is not defined, therefore can not be used
2) getCOJsonPath is not a static function, but you try to call it as static (again you have to use ->
so, the code should look something like this:
public function getCO() {
$siteConfig = SiteConfig::current_site_config();
$buffer = self::createHttpRequest($siteConfig->getCOJsonPath());
return $buffer;
}
that should work, but there is another think that could be improved.
As I understand it, you are creating an ajax page, which you then create once in the CMS and tell your website content authors never to touch the ajax page?
This is quiet ugly, and there are several nice ways to do what you want to do.
Here is how I would create an Ajax controller:
_config.php
// tell SilverStripe what URL your AjaxController should have,
// here we set it to AjaxController::$URLSegment which is 'myAjaxController'
// so the url to the controller is mysite.com/myAjaxController
Director::addRules(100, array(
AjaxController::$URLSegment => 'AjaxController',
));
AjaxController.php
<?php
class EventAssetsController extends Controller {
public static $URLSegment = 'myAjaxController';
// tell SilverStripe what URL should call what function (action)
// for example, mysite.com/myAjaxController/foo should call the function foo
public static $url_handlers = array(
'foo' => 'foo',
'bar/$ID/$OtherID' => 'bar',
'co' => 'getCO'
);
public function Link($action = null) {
// this function is just a helper, in case you evern need $this->Link()
return Controller::join_links(self::$URLSegment, $action);
}
public function AbsoluteLink($action = null) {
return Director::absoluteURL($this->Link($action));
}
public function foo(SS_HTTPRequest $request) {
// do something here
// this method is an action, the url to this action is:
// mysite.com/myAjaxController/foo
}
public function bar(SS_HTTPRequest $request) {
// do something here
// this method is an action, the url to this action is:
// mysite.com/myAjaxController/bar
// you notice that the $url_handlers has "bar/$ID/$OtherID",
// that means you cann call mysite.com/myAjaxController/bar/21/42
// and silverstripe will make 21 the ID, and 42 the OtherID
// you can access ID and OtherID like this:
// $ID = $request->param('ID'); // which is 21
// $OtherID = $request->param('OtherID'); // which is 42
}
public function getCO() {
// this method is an action, the url to this action is:
// mysite.com/myAjaxController/co
$siteConfig = SiteConfig::current_site_config();
$buffer = self::createHttpRequest($siteConfig->getCOJsonPath());
return $buffer;
}
}
I have a weird problem. Hopefully, there's a simple explanation / a simple bug somewhere in my code.
I have methodA in my controller, that needs 3 parameters from the url. The code looks like this:
$data['listofpts'] = $this->sw_model->get_all_widgets($this->uri->segment(3),$this->uri->segment(4) );
$data['model'] = $this->uri->segment(4);
$data['ip'] = $this->uri->segment(3);
$data['objectid'] = $this->uri->segment(5);
$data['main_content']='allstats';
$this->load->view('includes/template', $data);
You can see that I'm grabbing 3 pieces of from the url.
I have 2 additional methods (lets call them methodB and methodC) in the same controller and both of them, when complete, call methodA. However, when these other methods call methodA, the url looks different. Specifically, the "objectid" variable can be either segment 6 or 7 instead of segment 5.
here's an example of what the URL looks like when methodA is called:
http://myserver/myapp/mycontroller/methodA/10.14.123.123/H8699A/417
Here's an example of what the URL looks like when methodB is called:
http://myserver/myapp/mycontroller/methodB/10.14.3.44/H8699A/A14/417
I'm not sure if this is good design or not, but I decided to change the signature of methodA so that it accepts a number, representing the segment ID.
So from methodB, I could do something like:
$this->methodA(6);
PROBLEM / QUESTION: There are two things that i don't understand. The first question is why the new parameter is displaying a value when you just call methodA on its own. As soon as the ivew "allstats" loads, it shows a value inside the new parameter. Technically, it should be empty. I've double checked to make sure that only 2 methods call methodA.
Second, I don't understand why when i dump the contents of the parameter, its showing the IP address, which is uri segment 3.
So far, the new code for methodA looks like this:
public function methodA($uriObjectid)
{
echo $uriObjectid;
$data['listofpts'] = $this->switches_model->get_all_widgets($this->uri->segment(3),$this->uri->segment(4) );
$data['model'] = $this->uri->segment(4);
$data['ip'] = $this->uri->segment(3);
$data['objectid'] = $this->uri->segment(5);
$data['main_content']='allstats';
$this->load->view('includes/template', $data);
}//end methodA
Any help would be appreciated.
Thanks.
EDIT 1
This is what my controller looks like:
public MyController extends CI_Controller {
public methodA($optionalparm)
{
//url looks like: http://myserver/myapp/thiscontroller/value1/valueformethodA
echo $optionalparm; //this is the variable that's problematic. it should be 3 or 4.
$valueformethodA = $this->uri->segment(2)
}
public methodB() {
//url looks like: http://myserver/myapp/thiscontroller/value1/value2/value3/valueformethodA
//call methodA
// $valueformethodA is now uri segment 4. pass that as argument
$this->methodA(4);
}
public methodC() {
//url looks like: http://myserver/myapp/thiscontroller/value1/value2/valueformethodA
//call methodA
// $valueformethodA is now uri segment 4. pass that as argument
$this->methodA(3);
}
}
I'm not following your question 100%, and i'm unsure how the url is changing in between calling methodB and methodC and calling methodA, unless you're doing some sort of redirect.
If i have this url
http://example.com/myController/methodB/segment3/segment4/segment5/segment6
And i have this controller
public MyController extends CI_Controller {
public methodA() {
// the url should still be the same in here as it was in methodB unless a redirect was called.
}
public methodB() {
// call methodC
$this->methodC();
}
public methodC() {
// call methodA
$this->methodA();
}
}
In Codigniter, if i have a method that is called from a url like this:
public testMethod($one, $two, $three) {
}
$one is always going to be $this->uri->segment(3), $two is always going to be $this->uri->segment(4), and $three is always going to be $this->uri->segment(5);