I'm pretty new to code igniter.
Is there best practice for serving different view for different context.
For example, I'd like to serve specific pages for mobile user agents with the same controllers.
There isn't a hard rule for this. You can structure your view files however you like, and call $this->load->view() to load different view files for different outcomes in your controller. From my experience, CodeIgniter adapts very openly to how you organize your application's files.
In your example, perhaps I'd divide my system/application/views folder into two subfolders: main for desktop browsers, and mobile for mobile browsers:
system/
application/
views/
main/
index.php
some_page.php
...
mobile/
index.php
some_page.php
...
In an early part of your controller, say the constructor, you can decide what user agent is requesting it and then pick main or mobile based on that, then show your views accordingly from your controller actions.
Some quick code snippets to give you a better idea since you're new...
// Place this just below the controller class definition
var $view_type = 'main';
// Controller constructor
function MyController()
{
parent::Controller();
if ($this->agent->is_mobile())
{
$this->view_type = 'mobile';
}
else
{
$this->view_type = 'main';
}
}
// Example action
function some_page()
{
// ...
// This comes from the 'var $view_type;' line above
$this->load->view($this->view_type . '/some_page');
}
And some helpful references for you to explore:
Views in CodeIgniter
User Agent Class
Hope my explanation helps, and hope you have fun with CodeIgniter :)
Related
I'm going through some of the code and projects provided here http://fatfreeframework.com/development. My goal is to create a lightweight MVC kickstarter projecting using F3. I know it's been done before, but I'm using this as a learning exercise and I hope to have something useful come out of it in the end.
The biggest stumbling block I'm coming across right now is the concept of layouts. I know the documentation mentions using templates within templates, but I'm struggling to implement it in practice. In the end, I want to have 1 or 2 layouts (default layout, maybe a custom one for modal popups, etc), and then have my views rendered wrapped inside of those layouts. I want a default layout and then the ability to override the default for the few pages that need custom ones. Here's the code I've been using:
// this is the handler for one of my routes, it's on a controller class called Index
public function index($f3, $params)
{
// this (or anything else) should get passed into the view
$f3->set('listOfItems',array("item1", "item2"));
// set the view
$f3->set('content', 'index.htm')
// render the layout
\Template::instance()->render('layout.htm');
}
Unfortunately, I keep getting a blank page. Am I going about this completely the wrong direction, or am I on the right track? Is there a way to set a default layout somewhere so it's used until it's overridden?
Well you could create a base class with a default layout. Then you extend it for each controller class. For example:
abstract class Layout {
protected $tpl='layout.htm';
function afterRoute($f3,$params) {
echo \Template::instance()->render($this->tpl);
}
}
Then:
class OneController extends Layout {
function index($f3,$params) {
$f3->set('listOfItems',...);
$f3->set('content','one/index.htm');
}
}
class AnotherController extends Layout {
protected $tpl='popup.htm';//override default layout here
function index($f3,$params) {
$f3->set('listOfItems',...);
$f3->set('content','another/index.htm');
}
}
In layout.htm:
<body>
<div id="content">
<include href="{{#content}}" if="isset(#content)"/>
</div>
</body>
Structure of the UI folder:
/ui
|-- layout.htm
|-- popup.htm
|-- one
|-- index.htm
|-- another
|-- index.htm
This is just one example of how you could organize your code. F3 is loose enough to let you organize it in a multitude of ways.
I had exactly the same problem - set everything up as required, rendered the layout, and kept getting a blank page. Also when I checked the HTML source of the rendered page it was completely empty.
If you look closely however rendering the layout is not enough, you have to also print it using the echo command. So rather than the following example which appears at first glance to be correct:
$f3->route('GET /',
function($f3) {
// Instantiates a View object
$view = new View;
// Render the page
$view->render('template/layout.php');
you actually need the last line to start with echo:
echo $view->render('template/layout.php');
For more examples see:
http://fatfreeframework.com/views-and-templates
https://www.digitalocean.com/community/tutorials/how-to-use-the-fat-free-php-framework
http://takacsmark.com/fat-free-php-framework-tutorial-4-database-models-crud/
Also for some reason (which I'm sure will become clear soon - I've only just started using the Fat Free Framework) you seem to also be able to render an .htm file which contain embedded PHP (i.e. they don't have to have the .php extension).
For organizational purposes I need to have subfolders in my views directory. For example for managing login / registration: views/login_reg/login.php and views/login_reg/register.php.
In my URI want to see: www.mysite.com/login or www.mysite.com/register instead of www.mysite.com/login_reg/login.
I have tried the following in routes:
$route['(:any)/login'] = 'login_reg/login';
Which does not work.
EDIT:
A simple example to elaborate further:
//Controller: login_reg.php
class Login_reg{
function login(){
$this->load->view('login_reg/login');
}
function register(){
$this->load->view('login_reg/register');
}
}
//Routes:
$route['login_reg/(:any)'] = 'login_reg/$1';
So my URI looks like this: www.mysite.com/login_reg/login, or www.mysite.com/login_reg/register
So I want one controller to manage all login / registration related views. But I do not want to see the controller name in the URI. Is this possible? Or is the best approach to have a controller for login, a controller for registration, a controller for password changing etc? This seems a bit excessive. I want to have my files well organised into related directories as this is part of a very large site.
Here you don't need routing at all.
Simply add your folder name while loading view.
For example your controller name for login is like
function login()
{
//code goes here
$this->load->view('login_reg/login');
}
and similar for register.
Hope this helps you.Feel free to let me know if you further queries.
--- Update ---
To hide controller name make chanes in route.php like this;
$route['login'] = 'login_reg/login';
$route['register'] = 'login_reg/register';
and your url will go like this now :
http://yourwebsite.com/login
I have a site that has a lot of pages that lye at the root (ex. /contact, /about, /home, /faq, /privacy, /tos, etc.). My question is should these all be separate controllers or one controller with many methods (ex. contact, about, index within a main.php controller )?
UPDATE:
I just realized that methods that are within the default controller don't show in the url without the default controller (ie. main/contact wont automatically route to /contact if main is the default controller ). So you would need to go into routes and override each page.
If all of these are just pages, I would recommend putting them into a single controller. I usually end up putting static pages like this into a 'pages' controller and putting in routes for each static page to bypass the '/pages' in my URLs.
If they are share the same functionality, so they should be in the same controller.
for example, if all of them are using the same model to take content from, so, one controller can easily handle it.
Why in one controller? because you always want to reuse your code.
class someController{
function cotact(){
print $this->getContentFromModel(1);
}
function about(){
print $this->getContentFromModel(2);
}
function home(){
print $this->getContentFromModel(3);
}
private function getContentFromModel($id){
return $this->someContentModel->getContentById($id);
}
}
(instead of print, you should use load a view)
See in my example how all of the function are using the same getContentFromModel function to share the same functionality.
but this is one case only, there could be ther cases that my example can be bad for...
in application/config/routes.php
$route['contact'] = "mainController/contact";
$route['about'] = "mainController/about";
$route['home'] = "mainController/home";
$route['faq'] = "mainController/faq";
$route['privacy'] = "mainController/privacy";
and you should add all of these methods within the mainController.php
You can also save the content of the pages in your database, and them query it. For instance, you can send the url as the keyword to identify the page content
$route['contact'] = "mainController/getContent/contact";
$route['about'] = "mainController/getContent/about";
$route['home'] = "mainController/getContent/home";
$route['faq'] = "mainController/getContent/faq";
$route['privacy'] = "mainController/getContent/privacy";
in this case you only have to create one method named "getContent" in the controller "mainController" and this method will look something like this:
class mainController extends CI_Controller
{
public function getContent($param)
{
$query = $this->db->get_where('mytable', array('pageName' => $param));
// then get the result and print it in a view
}
}
Hope this works for you
The page names you listed should probably be different methods inside your main controller. When you have other functionality that is related to another specific entity, like user, you can create another controller for the user entity and have different methods to display the user, update the user, register the user. But its all really a tool for you to organize your application in a way that makes sense for your domain and your domain model.
I've written a blog post about organizing CodeIgniter controller methods that might be helpful to you. Check it out here: http://caseyflynn.com/2011/10/26/codeigniter-php-framework-how-to-organize-controllers-to-achieve-dry-principles/
I am trying to build a nice PHP framework for personal use. I realize there are many existing but this is a great learning experience that covers a vast majority of different challenges and really teaches me a lot, as well as having a finished product when i'm done that I can hopefully use to develop other projects from and since I am building it, there should be no learning curve on how to use it.
Some of the basic goals,
- Use PHP Object Oriented instead of procedural.
- Use an MVC or something similar to learn more about this style.
- Be lightweight and fast/good performance
Here is my planned site structure, excluding some other folders for javascript, images, css, some helper functions/files, etc.
///////////// Site structure /////////////
site.com/
/index.php
site.com/library/
/Config.class.php
/Photos.class.php
/Mail.class.php
/Filter.class.php
/QRcodes.class.php
/Router.class.php
/Database.class.php
/Templates.class.php
/etc, etc,etc......
site.com/modules/
/account/
/model
/views
/controllers
/users/
/model
/views
/controllers
/messages/
/model
/views
/controllers
/API/
/model
/views
/controllers
/forums/
/model
/views
/controllers
/blogs/
/model
/views
/controllers
/etc, etc, etc, etc.............
/model
/views
/controllers
I have decided to route all Request through a single point of entry, index.php
I will build a Router class/object that will match the URI against a map of possible destinations using regular expressions. Here is a snippet of what I have for now for this part...
<?php
//get url from URL
$uri = isset($_GET['uri']) ? $_GET['uri'] : null;
$uri_route_map = array(
//users/account like http://mysite.com/users/324 (any digit)
'users/friends/page-(?<page_number>\d+)' => 'modules/users/friends/page-$1',
'users/friends/edit/page-(?<page_number>\d+)' => 'modules/users/friends/edit/page-$1',
'users/friends/edit' => 'modules/users/friends/edit',
'users/friends/' => 'modules/users/friends/',
'users/online' => 'modules/users/online/' ,
'users/online/page-(?<page_number>\d+)' => 'modules/users/online/page-$1',
'users/create' => 'modules/users/create',
'users/settings' => 'modules/users/settings',
'users/logout(?<page_number>\d+)' => 'modules/users/logout',
'users/login' => 'modules/users/login',
'users/home' => 'modules/users/home',
//forums
'forums/' => 'modules/forums/index',
'forums/viewthread/(?<id_number>\d+)' => 'modules/forums/viewthread/$1',
'forums/viewforum/(?<id_number>\d+)' => 'modules/forums/viewforum/$1',
'forums/viewthread/(?<id_number>\d+)/page-(?<page_number>\d+)' => 'modules/forums/viewthread/$1/page-$2',
'forums/viewforum/(?<id_number>\d+)/page-(?<page_number>\d+)' => 'modules/forums/viewforum/$1/page-$2',
// TESTING new method to define class and page better!
'users/home' => array('PAGE CLASS NAME', 'ACTION NAME')
//blog routes coming soon
//mail message routes coming soon
//various other routes coming soon
);
//////////////////////////////////
class Router
{
public function __construct()
{
}
public function get_route($uri, array $uri_routes)
{
foreach ($uri_routes as $rUri => $rRoute) {
if (preg_match("#^{$rUri}$#Ui", $uri, $uri_digits)) {
//if page number and ID number in uri then set it locally
$page_number = (isset($uri_digits['page_number']) ? $uri_digits['page_number'] : null);
$id_number = (isset($uri_digits['id_number']) ? $uri_digits['id_number'] : null);
echo '<hr> $page_number = ' . $page_number . '<BR><hr> $id_number = ' . $id_number;
$uri = preg_replace("#^{$rUri}$#Ui", $rRoute, $uri);
echo '<BR><BR>Match found: ' . $uri_routes . '<BR><BR>';
break;
}
}
$uri = explode('/', $uri);
}
}
$uri = new Router();
$uri = $uri->get_routes($_GET['uri'], $uri_route_map);
?>
PLEASE NOTE
THE CODE ABOVE IS ALL TEST CODE AND WILL BE CHANGED, IT IS JUST THE CONCEPT
So as you can see I am planning to have index.php get the URI, check it against valid paths, if one is found, it will include or build a header section, then will build the content section, then finally the footer section of the page.
If you were to access for example... www.test.com/blogs/userid-32423/page-23
The the page would...
build header()
create object blogs... $blogs = new Blogs;
call $blogs->viewbyID($userID,$paging); //$userID would be 32423 and $paging would be 23 from the URI
build footer section
Now based on my folder structure. I believe that the blogs class file in our above example would be considered the CONTROLLER. If I am correct so far, then this blogs class which is calling blogs->viewbyID(ID,PAGE) the viewbyID method would set up some code, query the database and set up some variables for the page and then it could include a blogs template file. This blogs template file could be considered the VIEWS.
Now I might have this whole concept wrong, and that is why I posted so much code and text to try and explain my outlook on it, please give me thoughts, suggestions, tell me where im completely wrong, and where I might be on the right track, I will greatly appreciate any constructive critism or thoughts. If I am right in my above usage of the View, Controller portion of the MVC pattern, then what part of my code would be considered the Modal? This is somewhat confusing to me for some reason.
Bonus question... What about form post, where should I process these at? In my example I am focusing on the blog module, so lets say POST for adding new blog entry and POST for editing blog entry, where should these be processed (modal, view, controller)?
The controller's job is to examine the user's input and determine what is being requested. Once that's determined, the model(s) is invoked. The controller then takes the model's payload and gives it to the view.
Basically, the model is a model of the business. Want to add a blog post? Then the Blog model will have a ->add or ->save method (which is called by the controller. The blog controller may also have an add method, but it is not for talking to the database. It's for examining the input and then calling the model to do the actual saving). Model methods don't always interact with a database but they usually do.
As far as add/edit, they almost always share the same view and can share the same controller methods if doable.
Just remember that the controller is the entry point for all your clients. Every URL your application handles should map to a controller method. The controller then tells the model what to do, passing the user input to it.
Your Models should be the one querying the database, not your Controller. Your Model is there to handle all CRUD actions and, where necessary, pass results back to the Controller to hand to the View. Usual flow would be
Controller > Model > Controller > View
Im new to symfony and have some simple questions. I am trying to understand the module system, but I dont understand how I create the actual homepage or other pages that are not based off of a model from the db. For example, the simple about page that has static info or the homepage that is a combination of a bunch of information from different models.
Can anyone help?
First of all, modules do not have to be restricted to a model from the database. You can have a Foo module which relies on no database content, and a Bar module that is primarily based on 3 different models. The module separation is a way to logically break up your site into manageable sections. Eg an e-commerce site might have a Products module, a Categories module and a Cart module and so on.
Your last sentence can then be split into 2 parts:
1) Static information can be on any page - if it's for things like "About us" and "FAQ" etc, I personally tend to use a "default" or "home" module, and create the various actions in there vis:
./symfony generate:module appname home
and
class homeActions extends sfActions
{
public function executeAbout(sfWebRequest $request)
{
// ...
}
public function executeFaq(sfWebRequest $request)
{
// ...
}
}
with the corresponding template files (aboutSuccess.php, faqSuccess.php).
2) A page can be comprised of data from many different models - just use your preferred ORM's method of retrieving data and set it to the view ($this->data = MyModel->findByColumn(...) etc). If you mean data from different modules, then you'd probably be better off looking at partials or components for elements of a page that can be used across different modules (navigation etc). See the Symfony docs for more details on these.
I'm used to handle static pages in this way.
First I create a new entry in apps/frontend/config/routing.yml:
page:
url: pages/:page
param: { module: page, action: index }
Then I write a "page" module (apps/frontend/modules/page/actions/actions.class.php):
<?php
class pageActions extends sfActions
{
public function executeIndex()
{
$this->page = $this->getRequestParameter("page");
$this->forward404Unless($this->_partialExists($this->page));
}
protected function _partialExists($name)
{
$directory = $this->getContext()->getModuleDirectory();
return (is_readable($directory.DIRECTORY_SEPARATOR."templates".
DIRECTORY_SEPARATOR."_".$name.".php"));
}
}
Last step, put in modules/page/templates/indexSuccess.php this code:
<?php include_partial($page); ?>
So all you have to do from now is to create a partial for each static page ie.
apps/frontend/modules/page/templates/_home.php which you can reach at
http://yousite/pages/home (without the need to add a new routing entry for every page)
You can create a module, e.g. called static and create actions for every static page or only one action that delivers the page depending on a request variable. The only thing this action does is loading a template.
IMHO it would be good if symfony comes with a default module for this.
For example actions of (my custom) module static:
class staticActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
if(!$request->hasParameter('site')) {
return sfView::ERROR;
}
$this->site = $request->getParameter('site');
}
}
With this template:
//indexSuccess.php
<?php include_partial($site) ?>
The actual statics sites are all partials.
In my routing.yml looks like this:
# static stuff
about:
url: /about
param: {module: static, action: index, site: about}
This way you only have to create a new partial and a new routing entry when you add a static site and you don't have to touch the PHP code.
Another way to serve static pages without having to write any controller code is to set up the route something like the following:
myStaticPage:
pattern: /pageName
defaults:
_controller: FrameworkBundle:Template:template
template: MyBundle:Home:pageName.html.twig
Then just create your twig template and it should work fine.
Apart from the above, consider having a CMS for static pages, so you won't need technical savy people to mantain them or change them. This depends on the project, of course.
For really static and independent pages you can simply create any file in [pathToYourProjectRoot]/web directory.
It may by i.e. [pathToYourProjectRoot]/web/assets/static_html/about.html.
Then link to the page directly by http://your.site.com/assets/static_html/about.html.