Can anyone tell me how can I define and use a specific layout for a model (not a template)? I would like to do this for my custom 404 error page.
As Peter Bailey commented above, your layout is a component of the view and has nothing to do with models. Therefore you'd be able to do something like this in the actions module you're using (normally default):
public function executeError404(sfWebRequest $request)
{
$this->setLayout("your_layout_name");
// ...
}
and then in your [APPNAME]/templates directory, create the your_layout_name.php template file as you would with any other template.
Related
Is it possible to render another "root" template instead of the Page.ss file for some specific pages / controllers? There are already some pages using the Page.ss template, but now there will be a new "Intranet" section on the website where the pages should have another "root" template: IntranetPage.ss.
Page.ss should stay as is and should not be touched at all.
I mainly want different "root" templates because both templates load different JS and CSS files. Also the "container" HTML is quite different.
I was able to create a custom controller which does manually what I need. Something like this:
class IntranetPageController extends PageController
{
public function index()
{
return $this->customise([
'Layout' => $this->renderWith(['Intranet/Layout/IntranetPageLayout'])
])->renderWith(['Intranet/IntranetPage']);
}
}
The code is inspired from here: https://docs.silverstripe.org/en/4/developer_guides/templates/rendering_templates/
IntranetPage.ss is used now as the "root" template. IntranetPageLayout.ss is displayed for the $Layout placeholder.
That seems to work, however I have many pages which have to be based on IntranetPage.ss. It feels strange to write for every new Controller the very same index function (with a small adjustment to load another LayoutPage).
I am sure, Silverstripe has some convention to do that automatically :)
What I need is very close to having a individual theme per page, but I am not sure if that is possible...
Instead of extending PageController, extend your IntranetPageController in new controllers. Whenever index is called, it will call your index function from your parent class, in your case IntranetPageController.
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/
How could I prevent mentioned plugin's login form from using default layout? I am aware of this question, but that answer doesnt work for me. For starters, there's no signin module in modules dir, probably plugins handle it in different way, I dont know. Just learning symfony. Thanks in advance :)
For now its not possible to set custom layout for some sfGuardAuth action via custom view.yml.
This is how I did it.
This is my apps/backend/modules/sfGuardAuth/actions/actions.class.php:
<?php
require_once(sfConfig::get('sf_plugins_dir').'/sfDoctrineGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php');
class sfGuardAuthActions extends BasesfGuardAuthActions
{
public function preExecute()
{
$layout = $this->getActionName() == sfConfig::get('sf_login_action') ? 'sfGuardLayout' : $this->getLayout();
$this->setLayout($layout);
}
}
If you just want to set a different layout, you need to add a module (just create it manually) called "sfGuardAuth". Inside the /config/ directory for that, change the layout in the view.yml like for any other module. This is explained in:
http://www.symfony-project.org/plugins/sfDoctrineGuardPlugin/4_0_0
... under section "Customize sfGuardAuth module actions".
However, if you want to "embed" your login form on another existing page, you could turn the login into a component - which means it uses the existing layout of the page it occurs in.
Component action in a custom module:
public function executeSigninLightbox(sfWebRequest $request)
{
$class = sfConfig::get('app_sf_guard_plugin_signin_form', 'sfGuardFormSignin');
$this->form = new $class();
}
... which like all components uses a partial as its view. The partial now has access to $form like a standard login page. The partial for this would be called "_signinLightbox".
Hope that helps.
Can you tell me how to use a controller for home page because i'm trying to put a model's data in home.ctp (homepage view) with
<?php $this->user->find() ?>but it returns
Notice (8): Undefined property:
View::$user [APP\views\pages\home.ctp,
line 1]
You should check out the cookbook; it has some solid CakePHP tutorials, at http://book.cakephp.org/
You haven't really provided alot of information, but my guess is your Controller uses a model 'User', and you're putting $this->user->find() in your view, when it should be in your controller. In your controller's action you'll want/need to do something like this...
Users_Controller extends AppController {
function index() {
$arrayOfUsers = $this->User->find(...);
$this->set('users', $arrayOfUsers);
}
}
You can then - in your View - access 'users' like so:
pre($users);
... since you used the Controller method set() to send a variable $users to the view.
All you really need to do is create a new controller if that's the direction you want to go. If this is the only statement you have that requires data access, it might be worth faking it in only this method of the PagesController. For example, one of my projects' homepages is 99% static save for a list of featured events. Rather than move everything out to a new controller or even loading my Event model for the entire PagesController (where it's not needed), I just applied this solution in PagesController::home():
$attractions = ClassRegistry::init ( 'Attraction' )->featured ( 10 );
Works great. If your page is more dynamic than mine, though, it may well be worth routing your homepage through a different controller (one that is more closely related to the data being displayed).
The default controller for the home page i.e home.ctp view, is located in /cake/libs/controller/pages_controller.php. This controller can be overriden by placing a copy in the controllers directory of your application as /app/controllers/pages_controller.php. You can then modify that controller as deem fit i.e. use models, inject variables to be used in the home page etc
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.