I am working on a site where I have a map for each city I need e.g 'London.blade.php', 'Paris.blade.php'.
I a trying to implement a search bar on the site and I need it to return the views(blade.php pages) as the results, not contents of the views.
e.g where('views', 'LIKE', "%$search_query%").Is this actually possible as the views are not stored in the database, if so does anyone know how to go about this?
Here's a general-purpose function to list any file with the extension you specify, in this case, .blade.php. It starts searching at $path and then recursively searches any sub-directories it finds.
function findFileExtension_r($extension, $path, &$names = array()){
$files = array_diff(scandir($path), array('..', '.'));
foreach($files as $f){
$abs_path = $path.'/'.$f;
if(is_dir($abs_path)){ //directory, recurse
findFileExtension_r($extension, $abs_path, $names);
} else { //file, test if the name ends with $extension
$ext_length = strlen($extension);
if(substr($f, -$ext_length) === $extension){
$names[] = $f;
}
}
}
}
Usage:
//set up some values
$find = '.blade.php';
$path = 'path/to/laravel/resources/views';
//$blade_templates = array(); //can be initialized, or named in the function call below.
//call function
findFileExtension_r($find, $path, $blade_templates);
//output
echo '<h2>Results</h2><pre>' . print_r($blade_templates, true) . '</pre>';
You can actually store your blade templates in the database and query them via SQL: https://github.com/delatbabel/viewpages
If the views are not stored in the db, you'll have to point to the view in the routes and you can use a dynamic route.
Route::get('/{slug}', array('as' => 'page.show', 'uses' => 'PageController#show'));
The show function:
public function show()
{
$slug = input::get('location');
$page = page::whereSlug($slug)->get();
return View::make('pages')->with('page', $page);
}
Related
In .NET using AttributeRouting we can add the Route for each Action Method. Something like below
[HttpGet, Route("Create-Project")]
public ActionResult CreateProject()
{
return View();
}
So, in the above code...line 1 indicates that we can mention the route for each Action Method. So url will become something like below..
http://domainname/Create-Project
Question
Is it feasible in PHP MVC CI ? and right now I will have to write the code in route.php in config folder.
In routes.php you can define it
Syntax
$route['short_url_name'] = 'complete/path/for/url';
Example
$route['Contact-Us'] = 'home/contact';
$route['Blog'] = 'home/blog';
$route['Our-Work'] = 'home/work';
so URL look like
http://domain.com/Contact-Us
http://domain.com/Blog
http://domain.com/Our-Work
Codeigniter.com examples
In Application/config/router.php you can add some config like that:
$route['Create-Project'] = 'home/welcome';
So, each time you visit http://domain.com/Create-Project, it will redirect you to http://domain.com/home/welcome
If you are looking for database driven dynamic routes you can rty this, else you can follow what #abdulla has suggested.
Table structure for Dynamic routes(Table name example: routes).
id | slug |route
---------------------------------------------
1 |Pankaj |controller/method/id of user
2 |Abdulla |controller/method/id of user
3 |Niranjan |controller/method/id of user
In controller
$this->load->helper('text');
$slug = $this->input->post("username");// example if you want the username in url as route.
$slug = url_title(convert_accented_characters($slug), 'dash', TRUE);
$slug = $this->Routes_model->validate_slug($slug);
$route['slug'] = $slug;
$route_id = $this->Routes_model->save($route);
$route_id will have the id of route in routes table, insert the route id and slug in users table(For which table you want dynamic routes)
This is the code for route model
<?php
class Routes_Model extends CI_Model {
var $file_name;
function __construct()
{
parent::__construct();
$this->file_name = APPPATH.'config/routes'.EXT;
}
function check_slug($slug, $id=false)
{
if($id)
{
$this->db->where('id !=', $id);
}
$this->db->where('slug', $slug);
return (bool) $this->db->count_all_results('routes');
}
function validate_slug($slug, $id=false, $count=false)
{
if(is_numeric($slug))
{
$slug = '';
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
for ($i = 0; $i < 3; $i++)
{
$slug .= $characters[rand(0, strlen($characters) - 1)];
}
}
if($this->check_slug($slug.$count, $id))
{
if(!$count)
{
$count = 1;
}
else
{
$count++;
}
return $this->validate_slug($slug, $id, $count);
}
else
{
return $slug.$count;
}
}
function save($route)
{
// print_r($route);exit;
if(!empty($route['id']))
{
$this->db->where('id', $route['id']);
$this->db->update('routes', $route);
return $route['id'];
}
else
{
$this->db->insert('routes', $route);
return $this->db->insert_id();
}
}
}
?>
One condition i have checked is if the username is a number, i ll generate a length of 3 characters in validate_slug().
Now add the following code in core folder by file name MY_Router.php
<?php
class My_Router extends CI_Router
{
function __construct()
{
parent::__construct();
}
// this is here to add an additional layer to the routing system.
//If a route isn't found in the routes config file. then it will scan the database for a matching route.
function _parse_routes()
{
$segments = $this->uri->segments;
$segments = array_splice($segments, -2, 2);
// Turn the segment array into a URI string
$uri = implode('/', $segments);
// Is there a literal match? If so we're done
if (isset($this->routes[$uri]))
{
return $this->_set_request(explode('/', $this->routes[$uri]));
}
// Loop through the route array looking for wild-cards
foreach ($this->routes as $key => $val)
{
// Convert wild-cards to RegEx
$key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
// Does the RegEx match?
if (preg_match('#^'.$key.'$#', $uri))
{
// Do we have a back-reference?
if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
{
$val = preg_replace('#^'.$key.'$#', $val, $uri);
}
return $this->_set_request(explode('/', $val));
}
}
//look through the database for a route that matches and apply the same logic as above :-)
//load the database connection information
require_once BASEPATH.'database/DB'.EXT;
if(count($segments) == 1)
{
$row = $this->_get_db_route($segments[0]);
if(!empty($row))
{
return $this->_set_request(explode('/', $row['route']));
}
}
else
{
$segments = array_reverse($segments);
//start with the end just to make sure we're not a multi-tiered category or category/product combo before moving to the second segment
//we could stop people from naming products or categories after numbers, but that would be limiting their use.
$row = $this->_get_db_route($segments[0]);
//set a pagination flag. If this is set true in the next if statement we'll know that the first row is segment is possibly a page number
$page_flag = false;
if($row)
{
return $this->_set_request(explode('/', $row['route']));
}
else
{
//this is the second go
$row = $this->_get_db_route($segments[1]);
$page_flag = true;
}
//we have a hit, continue down the path!
if($row)
{
if(!$page_flag)
{
return $this->_set_request(explode('/', $row['route']));
}
else
{
$key = $row['slug'].'/([0-9]+)';
//pages can only be numerical. This could end in a mighty big error!!!!
if (preg_match('#^'.$key.'$#', $uri))
{
$row['route'] = preg_replace('#^'.$key.'$#', $row['route'],$uri);
return $this->_set_request(explode('/', $row['route']));
}
}
}
}
// If we got this far it means we didn't encounter a
// matching route so we'll set the site default route
$this->_set_request($this->uri->segments);
}
function _get_db_route($slug)
{
return DB()->where('slug',$slug)->get('routes')->row_array();
}
}
The above file is very important. As codeigniter first runs files inside core folder, this will create the slug you want. No need to add any routes in routes.php file.
Now while displaying users, you shud echo the slug in your users table.
Lets say controller name is users, method name is edit_user.
your controller code will look like this,
function edit_user($id){
// fetch the data related to $id, and load the view here
}
In url if it sees Niranjan, it will automatically take the route from routes table and will enter your function, edit_user().
Yes Method Looks Lengthy, but works perfect, i use this in all my ecommerce sites.
I was wondering if there was a way that I could list all the views load / included / extended in a response?
I know of laravel-debugbar, but I'd like to do it from within my code for Unit Testing purposes.
Just to clarify: I'm not looking to list all of the views in my resources folder. I'd like to get a list of all views used in the current response/request.
Thanks!
I have done something similar for myself. It's not perfect. Create the following route with function:
Route::get('list-views', function(){
$full_path = 'FULL-PATH-TO-YOUR-LARAVEL-VIEWS-FOLDER'; //LIKE /home/account/www/resources/views/
if(!is_dir($full_path))
return 'Views directory not found';
$files = scandir($full_path);
unset($files[0]);
unset($files[1]);
if(($key = array_search('emails', $files)) !== false) {
unset($files[$key]);
}
foreach($files AS $file){
$link = str_replace('.blade.php','',$file);
echo ''.$link.''.'<br>';
}
});
What this function does is checks if the views path exists which you define in the variable $full_path, scans that directory for view files. Now, list-views will list all available views.
laravel debugbar does that, but in my case i cant find a way to list all the views under the same url in one go, so if anyone nows how i would deeply appreciate it.
// EventServiceProvider#boot()
app('events')->listen('composing:*', function ($view, $data = []) {
$url = url()->current();
$view = $data[0];
$name = $view->getName();
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$url=>$path]);
});
another way could be but this will only display the main view "not the nested or parent"
// EventServiceProvider#boot()
use Illuminate\Foundation\Http\Events\RequestHandled;
app('events')->listen(RequestHandled::class, function ($event) {
$request = $event->request;
$response = $event->response;
$check = !$request->ajax() &&
!$request->pjax() &&
$request->isMethodCacheable() &&
$response->isSuccessful();
if ($check) {
$view = $response->original;
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$request->url(), $path]);
}
});
you can also get the view from a middleware but this will only display the main view same as b4
public function handle($request, Closure $next)
{
$response = $next($request);
$check = !$request->ajax() &&
!$request->pjax() &&
$request->isMethodCacheable() &&
$response->isSuccessful();
if ($check) {
$view = $response->original;
$path = ltrim(str_replace(base_path(), '', realpath($view->getPath())), '/');
logger([$request->url(), $path]);
}
return $response;
}
I am adapting StationWagon (FuelPHP app) and so far it's working really well.
I have adapted it (with some help) to allow multiple images to be uploaded to the server. This is also working great.
However, I am thinking it would make more sense if I had 2 Tables: 1) Articles and 2) ArticleImages. I would use a Foreign Key to associate the Images with the Article. So when publishing an article it would add the article data to 'Articles' table and move each image to a new row in 'ArticleImages'.
So ultimately my 'ArticleImages' table could be:
ID | ImageURL | ArticleID
Portion of my 'articles.php' controller:
<?php
public function action_add()
{
$val = Model_Article::validate('add_article'); //<-- maybe its just me but i never saw any similar to this in fuelphp sorry about this if im wrong
// if your form validation is okay than continue with everyhing else
if ($val->run())
{
$article = Model_Article::forge();
// Custom configuration for this upload
$config = array(
'path' => DOCROOT.DS.'images',
'randomize' => true,
'ext_whitelist' => array('img', 'jpg', 'jpeg', 'gif', 'png'),
);
Upload::process($config);
// if a valid file is passed than the function will save, or if its not empty
if (Upload::is_valid())
{
// save them according to the config
Upload::save();
//if you want to save to tha database lets grab the file name
$value = Upload::get_files();
foreach($value as $files) {
print_r($files);
}
$article->filename = $value[0]['saved_as'];
}
$status = (Input::post('save_draft') ? 0 : 1);
if ( ! $val->input('category_id'))
{
$category_id = null;
}
else
{
$category_id = $val->validated('category_id');
}
$article->user_id = $this->user_id;
$article->category_id = $category_id;
$article->title = $val->validated('title');
$article->body = $val->validated('body');
$article->published = $status;
if ($article->save())
{
Session::set_flash('success', 'Article successfully added.');
}
else
{
Session::set_flash('error', 'Something went wrong, '.
'please try again!');
}
Response::redirect('articles/add');
}
$this->template->title = 'Add Article';
$this->template->content = View::forge('articles/add')
->set('categories', Model_Category::find('all'), false)
->set('val', Validation::instance('add_article'), false);
}
/* End of file articles.php */
You are trying to make a relation between Articles and ArticleImages. An ArticleImage belongs to an Article, while an Article has many ArticleImages. FuelPHP has functionality built in for what you are trying to achieve. Have a look at the FuelPHP docs on its Object Relational Mapper, especially the Belongs To and Has Many relations.
So when i made the code for you back a few days a go you only requested, one file input.
And no offense but you are doing it all wrong...
foreach($value as $files) {
print_r($files);
}
$article->filename = $value[0]['saved_as'];
should be
foreach($value as $files) {
$articleimg = Model_Articleimages::forge();
$articleimg->image_row_name = $files['saved_as']
}
To get you to understand
what you did here, $value = Upload::get_files(); yes this gets all the elements but since you need to loop trouh the elements you dont need it
Second
this $value[0]['saved_as'] only grabs the first image name, just the first one, and since you are in a loop now you need to refer to the $files variable as i shown you in the above example, just an example
I have 4 files. I am trying pass my fetch results through a function to another page. My code is below:
File actions.php
public function getAction($action, $page, Array $vars){
if(!empty($action)){
$action = strtolower($action);
$path = $page.'/'.$action.'.php';
$currentTemplate = $this->loadActionTemplate($path);
return Array($currentTemplate, $vars);
}
else{
$action = strtolower($action);
$path = $page.'/default.php';
$currentTemplate = $this->loadActionTemplate($path);
return ($currentTemplate);
}
}
File news.php(controller)
$file = VIEWS_PATH.strtolower($this->template) . '.php';
if (file_exists($file)){
$currentQuery = $newsModel->viewQuery($selectQuery,$returnAll);
include_once($file);
}
}
File news.php(Main view)
$factory = new Actions_Factory();
$factory->getAction($action, $page, $currentQuery);
File view.php(sub View)
print_r($currentQuery);
I can't get $currentQuery to print out the mysql dump on view.php but $currentQuery prints out fine on news.php. I am doing something wrong and can't figure out what it is.
Any help would be much appreciated.
Thanks in Advance
$factory->getAction($action, $page, $currentQuery);
print_r($currentQuery);
You set $currentQuery to getAction(), but this function return result if you want function affect on argument you have to use assign by reference!
Insert "&" in $var to assign variable by reference
public function getAction($action, $page, Array **&$vars**){
I'm looking for a one line route to route dashed controller and method names to the actual underscored controller and method names.
For example the URL
/controller-name/method-name-which-is-long/
would route to
/controller_name/method_name_which_is_long/
see: http://codeigniter.com/forums/viewreply/696690/ which gave me the idea to ask :)
That is exactly my requirement too and I was using routes like
$route['logued/presse-access'] = "logued/presse_access";
In my previous project I needed to create 300-400 routing rules, most of them are due to dash to underscore conversion.
For my next project I eagerly want to avoid it. I have done some quick hack and tested it, though have not used in any live server, its working for me. Do the following..
Make sure the subclass_prefix is as follows in your system/application/config/config.php
$config['subclass_prefix'] = 'MY_';
Then upload a file named MY_Router.php in system/application/libraries directory.
<?php
class MY_Router extends CI_Router {
function set_class($class)
{
//$this->class = $class;
$this->class = str_replace('-', '_', $class);
//echo 'class:'.$this->class;
}
function set_method($method)
{
// $this->method = $method;
$this->method = str_replace('-', '_', $method);
}
function _validate_request($segments)
{
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).EXT))
{
return $segments;
}
// Is the controller in a sub-folder?
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);
if (count($segments) > 0)
{
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).EXT))
{
show_404($this->fetch_directory().$segments[0]);
}
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
// Does the default controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
{
$this->directory = '';
return array();
}
}
return $segments;
}
// Can't find the requested controller...
show_404($segments[0]);
}
}
Now you can freely use url like http://example.com/logued/presse-access and it will call the proper controller and function by automatically converting dash to underscore.
Edit:
Here is our Codeigniter 2 solution which overrides the new CI_Router functions:
<?php
class MY_Router extends CI_Router {
function set_class($class)
{
$this->class = str_replace('-', '_', $class);
}
function set_method($method)
{
$this->method = str_replace('-', '_', $method);
}
function set_directory($dir) {
$this->directory = $dir.'/';
}
function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).'.php'))
{
return $segments;
}
// Is the controller in a sub-folder?
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);
while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($this->directory . $segments[0]);
$segments = array_slice($segments, 1);
}
if (count($segments) > 0)
{
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).'.php'))
{
if ( ! empty($this->routes['404_override']))
{
$x = explode('/', $this->routes['404_override']);
$this->set_directory('');
$this->set_class($x[0]);
$this->set_method(isset($x[1]) ? $x[1] : 'index');
return $x;
}
else
{
show_404($this->fetch_directory().$segments[0]);
}
}
}
else
{
// Is the method being specified in the route?
if (strpos($this->default_controller, '/') !== FALSE)
{
$x = explode('/', $this->default_controller);
$this->set_class($x[0]);
$this->set_method($x[1]);
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
}
// Does the default controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
{
$this->directory = '';
return array();
}
}
return $segments;
}
// If we've gotten this far it means that the URI does not correlate to a valid
// controller class. We will now see if there is an override
if ( ! empty($this->routes['404_override']))
{
$x = explode('/', $this->routes['404_override']);
$this->set_class($x[0]);
$this->set_method(isset($x[1]) ? $x[1] : 'index');
return $x;
}
// Nothing else to do at this point but show a 404
show_404($segments[0]);
}
}
Now one has to place this file like application/core/MY_Router.php and make sure he has subclass_prefix is defined as $config['subclass_prefix'] = 'MY_'; in application/config/config.php
Few extra lines of code has been added in method _validate_request():
while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($this->directory . $segments[0]);
$segments = array_slice($segments, 1);
}
It is used so that one can make use of multi-level subdirectory inside controllers directory, whereas normally we can use single level subdirectory inside controllers folder and can call it in url. One can remove this code if it not necessary but it has no harm on the normal flow.
Just coming back to this question after upgrading to CodeIgniter 2. Here is a solution which is more robust than the accepted answer because it will survive CodeIgniter core updates.
<?php
class MY_Router extends CI_Router
{
public function set_class($class)
{
parent::set_class($this->_repl($class));
}
public function set_method($method)
{
parent::set_method($this->_repl($method));
}
public function _validate_request($segments)
{
if (isset($segments[0]))
$segments[0] = $this->_repl($segments[0]);
if (isset($segments[1]))
$segments[1] = $this->_repl($segments[1]);
return parent::_validate_request($segments);
}
private function _repl($s)
{
return str_replace('-', '_', $s);
}
}
It should be saved as application/core/MY_Router.php. Now, you can have Controller and Method names with underscores in them such as Abc_Def (in file abc_def.php) and refer to them with the URL /abc-def.
Actually this is native now in Codeigniter 3
Just do this in routes file
$route['translate_uri_dashes'] = TRUE;
And it will do it for controllers and methods automatically .
Please vote this answer up , as it's most recent
<?php
class MY_Router extends CI_Router
{
function _set_request($segments = array()) {
parent::_set_request(str_replace('-', '_', $segments));
}
}
?>
Put this file MY_Router.php inside /application/libraries (CI1) or /application/core (CI2)
Remember that this will effect all segments, not only module, controller and method.
Alternative to this extend is to add each segment to router.php
$route['this-is-a-module-or-controler'] = 'this_is_a_module_or_controller';
As you can see the extend method would be easier to use. You can choose to make the function also to handle only the first two or three segments so that the other segments are not affected with the _ replacement.
This is an old question, but I'd like to post that e-mike had a great solution to this problem, and a lot simpler.
<?php
public function _set_request($segments){
// Fix only the first 2 segments
for($i = 0; $i < 2; ++$i){
if(isset($segments[$i])){
$segments[$i] = str_replace('-', '_', $segments[$i]);
}
}
// Run the original _set_request method now, giving it our newly replaced segments
parent::_set_request($segments);
}
?>
Hope this helps anyone else with this problem.
I believe what you are looking for is a either a pre-system or else a pre-controller hook that will take the requested URI and update it.
Overriding the Router class is a nice approach, there is also a way of replacing - with _ by registering a "pre-system" hook.
First create the hook by adding these lines to your ‘config/hooks.php’ file:
$hook['pre_system'] = array(
'class' => '',
'function' => 'prettyurls',
'filename' => 'myhooks.php',
'filepath' => 'hooks',
'params' => array()
);
Now create a ‘myhooks.php’ file within the ‘application/hooks’ folder and add this function (don’t forget to open a PHP tag if this is the first hook):
<?php
function prettyurls() {
if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') {
$newkey = str_replace('-','_',key($_GET));
$_GET[$newkey] = $_GET[key($_GET)];
unset($_GET[key($_GET)]);
}
if (isset($_SERVER['PATH_INFO'])) $_SERVER['PATH_INFO'] = str_replace('-','_',$_SERVER['PATH_INFO']);
if (isset($_SERVER['QUERY_STRING'])) $_SERVER['QUERY_STRING'] = str_replace('-','_',$_SERVER['QUERY_STRING']);
if (isset($_SERVER['ORIG_PATH_INFO'])) $_SERVER['ORIG_PATH_INFO'] = str_replace('-','_',$_SERVER['ORIG_PATH_INFO']);
if (isset($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI'] = str_replace('-','_',$_SERVER['REQUEST_URI']);
}
You will probably need to edit your ‘config/config.php’ file to enable hooks (around line 91 for me):
$config['enable_hooks'] = TRUE;
This answer is ripped from http://codeigniter.com/forums/viewthread/124396/#644012
I'm not sure if you could do that with a route...
However, somewhere in the Codeigniter core libraries (possibly Router or URI) will be something that converts the underscored uris into a camelcase class name.
I had a quick look and couldn't find it, but if you do, just copy that library to your application/libraries folder, and modify it there.
You can use this _remap() method to handle such behavior. Place this method in your controllers or create a core controller and place it in.
public function _remap($method, $params = array()){
if(method_exists($this, $method)){
return call_user_func_array(array($this, $method), $params);
}else{
$method = str_replace("-", "_", $method);
if(method_exists($this, $method)){
return call_user_func_array(array($this, $method), $params);
}
}
show_404();
}