I love and hate Cakephp at the same time.
I need the current domain name and id in virtually every controller in a multi tenant site.
So, in the AppContoller beforeFilter...if I do this...
$dname = $_SERVER['HTTP_HOST'];
$this->set('domain',$dname); //only to show test output in the view.
I have access to $domain in the view without any problem.
Good so far. I know I have access to SERVER vars.
Then, my find function works fine when I hard code the domain name like this...
$this->loadModel('Domain');
$domainName = $this->Domain->find('first',array('conditions' => array('Domain.name' =>'test.localhost.com')));
However, when I try to use $dname within the condition like this, it fails.
$this->loadModel('Domain');
$dname = $_SERVER['HTTP_HOST'];
$domainName = $this->Domain->find('first',array('conditions' => array('Domain.name' => $dname)));
I'm feeling like I'm close, but... wth?
Oh my gosh. I am so embarrassed. It works fine. I didn't have an entry in the db for the domain I was using, so it couldn't find anything. Sorry.
Sometimes that whole forest/trees thing.... well you know.
You can pr($dname); within the before filter and it will show on every page. also you may want to try using strtolower() to make sure that no other letters are capitalized when putting it in the condition.
Related
I have a website where the front page contains a search form with several fields.
When the user performs a search, I make an ajax call to a function in a controller.
Basically, when the user clicks on the submit button, I send an ajax call via post to:
Route::post('/search', 'SearchController#general');
Then, in the SearchController class, in the function general, I store the values received in a session variable which is an object:
Session::get("search")->language = Input::get("language");
Session::get("search")->category = Input::get("category");
//I'm using examples, not the real variables names
After updating the session variable, in fact, right after the code snippet shown above, I create (or override) a cookie storing the session values:
Cookie::queue("mysite_search", json_encode(Session::get("search")));
And after that operation, I perform the search query and send the results, etc.
All that work fine, but I'm not getting back the values in the cookie. Let me explain myself.
As soon as the front page of my website is opened, I perform an action like this:
if (!Session::has("search")) {
//check for a cookie
$search = Cookie::get('mysite_search');
if($search) Session::put("search", json_decode($search));
else {
$search = new stdClass();
$search->language = "any";
$search->category = "any";
Session::put("search", $search);
}
}
That seems to be always failing if($search) is always returning false, and as a result, my session variable search has always its properties language and category populated with the value any. (Again: I'm using examples, not the real variables names).
So, I would like to know what is happening here and how I could achieve what I'm intending to do.
I tried to put Session::put("search", json_decode($search)); right after $search = Cookie::get('mysite_search'); removing all the if else block, and that throws an error (the ajax call returns an error) so the whole thing is failling at some point, when storing the object in the cookie or when retieving it.
Or could also be something else. I don't know. That's why I'm here. Thanks for reading such a long question.
Ok. This is what was going on.
The problem was this:
Cookie::queue("mysite_search", json_encode(Session::get("search")));
Before having it that way I had this:
Cookie::forever("mysite_search", json_encode(Session::get("search")));
But for some reason, that approach with forever wasn't creating any cookie, so I swichted to queue (this is Laravel 4.2). But queue needs a third parameter with the expiration time. So, what was really going on is that the cookie was being deleted after closing the browser (I also have the session.php in app/config folder set to 'lifetime' => 0 and 'expire_on_close' => true which is exactly what I want).
In simple words, I set the expiration time to forever (5 years) this way:
Cookie::queue("mysite_search", json_encode(Session::get("search")), 2592000);
And now it seems to be working fine after testing it.
One solution to automatically building navigation for a site is by scanning a folder for documents like this:
foreach(glob('pages/*.pg.php') as $_SITE_NAV_filePath):
$_SITE_NAV_filePath = explode('.pg',pathinfo($_SITE_NAV_filePath,PATHINFO_FILENAME));
$_SITE_NAV_fileName = $_SITE_NAV_filePath[0];
$_SITE_NAV_qv = preg_replace('/([A-Z])/','-$1',$_SITE_NAV_fileName); $_SITE_NAV_qv = trim($_SITE_NAV_qv,'-');
$_SITE_NAV_name = preg_replace('/([A-Z])/',' $1',$_SITE_NAV_fileName);
?>
<li><?=$_SITE_NAV_name?></li>
<?php
endforeach;
This code will turn "AnAwesomePage.pg.php" into a menu item like this :
<li>An Awesome Page</li>
This might be bad practice (?).
Anyway; I don't use this method very often since most of the time the sites have a database, and with that comes better solutions...
But my question is this:
Is there a way to prefix the filename with a integer followed by and underscore (3_AnAwesomePage.pg.php), for sorting order purposes, and pass it somehow to the destination page outside of the querystring and without any async javascript?
I could just explode the filename once again on "_" to get the sort order and store it somewhere, somehow?
This is the code for handeling the page query request:
$_SITE_PAGE['qv'] = $_GET['page'];
if (empty($_SITE_PAGE['qv'])){ $_SITE_PAGE['qv'] = explode('-','Home'); }
else { $_SITE_PAGE['qv'] = explode('-',$_GET['page']); }
$_SITE_PAGE['file'] = 'pages/'.implode($_SITE_PAGE['qv']).'.pg.php';
This code turns "An-Awesome-Page" back into "AnAwesomePage.pg.php" so it's possible to include it with php.
But with a prefix, it's not so easy.
The probliem is; Now there's no way to know what prefix number there was before since it has been stripped away from the query string. So I need to send it somehow along in the "background".
One very bad solution I came up with was to transform the navigation link into a form button and just _POST the prefix interger along with the form. At fist it sounded like a nice solution, but then I realized that once a user refreshes their page, it didn't look very good. And after all, that's not what forms are for either...
Any good solutions out there?
Or some other and better way for dealing with this?
There are two ways to keep that number saved, you can use cookies or php session variables.
But in this case, if user first enter the url in the browser or in a new browser, then he should be taken to default number.
Like you have:
1_first-page.php
2_first-page.php
3_first-page.php
If user enter the url like: domain.com/?page=first-page, you have to take him to 1_first-page.php to any number which you want to be default.
I am creating a website using the MVC structure. Below is a code I have used to use clean URLS and load the appropriate files. However it only works for the first level.
Say I wanted to visit mywebsite.com/admin it would work, however mywebsite.com/admin/dashboard would not. The problem is in the arrays, how could I get the array to load content after the 2nd level along with the second level.
Would it be best to create an array like this?
Array
- controller
- view
- dashboard
Any help here would be great. Also as a side question. What would be the best way to set up "custom" urls. So if I were to put in mywebsite.com/announcement it would check to see if its got controllers, failing that, check to see if it's got custom content (maybe a file of the same name in "customs" folder, and then if there's nothing execute the 404 page not found stuff) This isn't a priority question though, but loosely associated in how the code works so I thought it best to add.
function hook() {
$params = parse_params();
$url = $_SERVER['REQUEST_URI'];
$url = str_replace('?'.$_SERVER['QUERY_STRING'], '', $url);
$urlArray = array();
$urlArray = explode("/",$url);
var_dump($urlArray);
if (isset($urlArray[2]) & !empty($urlArray[2])) {
$route['controller'] = $urlArray[2];
} else {
$route['controller'] = 'front'; // Default Action
}
if (isset($urlArray[3]) & !empty($urlArray[3])) {
$route['view'] = $urlArray[3];
} else {
$route['view'] = 'index'; // Default Action
}
include(CONTROLLER_PATH.$route['controller'].'.php');
include(VIEW_PATH.$route['controller'].DS.$route['view'].'.php');
var_dump($route['controller']);
var_dump($route['view']);
var_dump($urlArray);
var_dump($params);
// reseting messages
$_SESSION['flash']['notice'] = '';
$_SESSION['flash']['warning'] = '';
}
// Return form array
function parse_params() {
$params = array();
if(!empty($_POST)) {
$params = array_merge($params, $_POST);
}
if(!empty($_GET)) {
$params = array_merge($params, $_GET);
}
return $params;
}
Can you clarify this: "The problem is in the arrays, how could I get the array to load content after the 2nd level along with the second level."
I don't understand how you want this thing to work. I checked your code and it works. Maybe you just need to put $urlArray[1] instead of $urlArray[2] and 2 instead of 3? First element in the array is at index 0.
Usually it's done like this:
Url format:
/controller/action/param1/param2/...
-controller- should be a class. That class has a method/function called -action-.
ex. /shoes/show/121/ --> this will load controller shoes
and execute the method/function show(121)
that will show the shoes that have the id 121 in the
database.
ex. /shoes/list/sport --> this will load controller shoes
and execute function list('sport') that will list all
shoes in the sport category.
As you can see, you only load one controller and from that controller you run only one function and that function will get the rest of the path and use it as parameters.
If you want to have multiple controllers for one URL, then the rest of the controllers will have to be loaded from the main controller. Most MVCs (like CodeIgniter) load only one controller per URL.
Second question:
Best way for pretty urls would be to save them in the db. This means you can have URLs like this:
/I-can-write-anything-here-No-need-to-add-ids-or-controller-names
Then you take this URL and search it in db and get the -controller- and -action- that you need for this URL.
But I have yet to see a popular MVC framework do this. I guess the reason is that the db will get a lot of queries for text matches and that will slow things down.
Popular MVC frameworks use:
/controller/action/param1/param2
This has the benefit that you can directly find the controller/action from the url.
The downside is that you will get urls like:
/shoes/list/sport
//when what you really want is
/shoes/sport
//or just
/sport //if the website only sells shoes
This can be fixed by redirecting /shoes/sport to /shoes/list/sport
If you make your own MVC then you should use OOP because if not, thing will get ugly quick: all actions/functions are in the same namespace.
Personally I would recommend that you use one of the many PHP frameworks that exist as that will take care of the routing for you and let you concentrate on writing your application. CakePHP is one that I've used for a while and it makes my life so much easier.
What I do:
I create a .htaccess file that redirects an url like www.example.com/url/path/or/something to www.example.com/index.php?url=url/path/or/something, so it will be pretty easy to do an explode on your $_GET['url']
Second, it's better because everything a user input, will be redirected to your index.php, so you have FULL control over EVERYTHING.
If you want I can PM you the url to my mvc (bitbucket) so you can have a look on how I do this ;)
(Sorry for the others, but I don't like to put url's to my site in public)
edit:
To be more precise to your particular question; It will solve your problem, because everything goes to index.php and you have full control over the requested url.
I am trying to call pages using Zend_Paginate() on a query that loads based on a GET search string the query essentially does the following:
SELECT * FROM table WHERE column LIKE '%searchstring%' OR alt_column LIKE '%searchstring%';
The query works fine when called via search/submit text form and the URL returns something similar to
URLINK.php?search=searchstring
However when trying to move onto the next page the program dumps me back to the paginate alternate URL (used for errors or no page display)-- hope this last line makes sense it is late and am doing my best to type this up with transparency.
What is the best method when using paginate against URL.php?search=searchstring"?
A bit more on the call to the url
//search query
$search = searchQuery('search', 'list_sql_rows.php');
$results - searchTable($dbRead, $search);
search method using the variables above in the order below
if(isset($_POST['submit_search'])) { $searchstring = $_POST['searchstring'];
if($searchstring) { header('Location: results.php?search=' . $searchstring); } }
This bit works well, but when I try to call the results.php?page=2 with paginator the system reverts me to the fall back URL list_sql_rows.php as mentioned above. Any thoughts/comments are appreciated.
Just to clarify a search field/form from the search.php page sends the $searchstring to the results.php page via $_POST && $_GET as fail safe. The get method sends the $searchstring in the URL header so the results of the search DO work on the first page results.php?search=$searchstring. This works just fine. The pagination seems to lose the $searchstring, and I wonder if this is due to a loss of the $_POST/$_GET when paginator begins to 'paginate' it returns URL results.php?page=2 so it seems $_GET may not be the method of choice?
UPDATE
On the write track now paginate works it is my link structure that is broken.
_results_samples.php?search=robert&page=4_ will in fact return page 4 of the paginated results using the word ROBERT
SOLUTION FOUND VIA variant suggestion by ROCKYFORD
variant of recommended method by first persisting $searchstring
change to paginate links as shown below
<a href='" . $_SERVER['PHP_SELF'] . "?search=" . $searchstring . "&page={$page}'>$page</a>
Here is the example of correct using of pagination:
in action-method:
$select = $clients->getAll();
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbSelect($select));
$paginator->setCurrentPageNumber($this->_getParam('page'));
$paginator->setItemCountPerPage(20);
$this->view->clients = $paginator;
in a view script:
<?php if (count($this->clients) > 0): ?>
...
<?php echo $this->paginationControl($this->clients, 'Sliding', 'partials/paginator.phtml'); ?>
<?php else: ?>
<h3 class="notice">No registered clients found!</h3>
<?php endif; ?>
But even if you will fail with this variant, you can always try to compose your own component, Zend only aids us in solving some tasks.
you need to make sure you preserve the query strings between requests, use Zend_Session_Namespace or Zend_registry.
Everytime Zend_Paginator loads a page when using the DbTableSelect or DbSelect adapters it has to hit the db with the query, it just changes the limit option.
Or you could just dump the whole query result into a Zend_Paginator_Adapter_Array and it will page through the array.
[edit]
you are going to have to persist the query string between requests someway so you can put it back in the url string, I usually use Zend_Registry, but then I use the whole MVC stack. You don't seem to be using the whole stack so you'll need another method, probably $_SESSION would work. I'm sure there are many other ways to persist this data.
P.S. you didn't mention which adapter you are using so I'm making some assumptions.
[edit]
Personally I always use $_post for this when possible to avoid all this, only seem to have this problem with $_get.
I am trying to load views for a set of 'modules' for a user who has selected any number of available 'modules'. I can get the name of the modules, or any column from the database.
load->view($name . '_view');
I can't seem to figure a way to load the data for the view based on the 'module' name though.
//Loads the rows (selected modules) I need for this user into an array
$modules['modulearr'] = $this->module_model->getModuleUser();
for($i = 0; $i < count($modules['modulearr']); $i++){
//Get the variable from the array
$name = $modules['modulearr'][$i]->mod_name;
//The below works.
$this->load->view($name.'_view');
//The below would not work. (this is the crux of my problem)
$data = $this->$name.'_model'->get();
$this->load->view($name.'_view', $data);
}
There is also an issue with loading the models in the controller based on the fact I can't change $this->load->THIS_PART dynamically.
I am new to everything, so there may be a basic concept I am not grasping. If you could point me in the right direction; that would be awesome. I could do a whole bunch of if statements, but that seems messy. Surely there is a better way. Thanks in advance!
maybe you wanted
$data = $this->$name.'_model'->get();
you forgot to concatenate the strings
but can't seem to figure a way to load
the data for the view based on the
'module' name.
The module name seems to be defined from the line
$name = $modules['modulearr'][$i]->mod_name;
if this works...
$this->load->view($name.'_view');
maybe you want to do this?
$data = $name.'_model'->get();
instead of $this->name ?
If that doesn't work (i don't really know what you have going on) try echoing $this->name and making sure the output makes sense attached to '_model'
It was a capitalization issue: The fields from the database (in array form)
$name = $modules['modulearr'][$i]->mod_name;
were sometimes in capitals. I fixed it by using
$name = strtolower($name);
$nameMod = $name.'_model';
then
//it doesn't seem to like combinations of things where nameMod is below.
$data[$name.'_result'] = $this->$nameMod->get()
$this->load->view($name.'_view', $data);
I don't know why it originally worked in the view loading part and not the loading data by calling model function part, but it does now. I am using it for a main landing (after sign up or login) page function that selects and displays the modules added by each user to their profile, I am probably going about this in a completely gammy way, but I am learning heaps by making mistakes, Thanks for the help answerers you definitely put me on the right track