Add the same calculated property to every Symfony2 Controller in bundle - php

I'm converting an application over from a legacy framework to Symfony2. One of the things the app has is a tiny little message in the bottom corner of the rendered page that says
served by appserver3 in 200ms
or similar. It changes depending on the appserver you're on and the amount of time it took to serve the request. The value for the appserver is set in a config file (but that's largely irrelevant here).
Should I create a BaseController type class that extends Controller and then have all my controllers extend that? If so, how would I go about making sure that the BaseController always adds the responseTime and appServerName to the list of variables that will be passed to my twig template without having to add it manually in every controller like this:
// e.g. src/MyNamespace/MyBundle/Controller/AboutUsController.php
return $this->render('MyNamespaceMyBundle:Default:index.html.twig', array('var1' => $var1, 'appServerName' => $this->getAppServerName(), 'responseTime' => $this->getResponseTime()));
(Obviously this would assume that I created the getAppServerName and getResponseTime methods in my BaseController.)
This seems like a lot of copypasta and my whole reason for moving to Symfony2 is to avoid that :\

Solution 1
For dynamic parts in the templates, especially in the base templates which are extended from every template, you can render the output from a controller action. It's like twigs include but it includes the dynamic content returned.
See Embedding Controllers in the documentation.
Outputting the served appserver is easy. Simply get the parameter from container. Calculating the load time may be a more complicated task and not really necessary for the user.
Solution 2
If it's only a static appserver parameter configured in your parameters.yml you can define it as a twig global variable in your config.yml:
twig:
globals:
appserver: "%appserver%"
Now you can include it in the needed twig template:
serverd from {{ appserver }}

Related

Dealing with Views in Phalcon Controllers

I am working on a newly created Phalcon project, and I don't really know how to actually use multiples views.
What is the entry point? I don't really know when each method in the controller is called, under which conditions, etc.
Where is the control flow defined? is it based in the name of the view? or is there a place where you can register them?
Phalcon is a bit different than other well-known PHP frameworks, in that not much is pre-configured or pre-built by default. It's quite loosely-coupled. So you have to decide where and how your control flow will work. This means that you will need to dig deeper in the documentation and also that there could be different way to achieve the same thing.
I'm going to walk you through a simple example and provide references, so you can understand it more.
1) You would start by defining a bootstrap file (or files) that will define the routes, or entry points, and will setup and create the application. This bootstrap file could be called by an index.php file that is the default file served by the web server. Here is an example of how such bootstrap file will define the routes or entry points (note: these are just fragments and do not represent all the things that a bootstrap file should do):
use Phalcon\Di\FactoryDefault;
// initializes the dependency injector of Phalcon framework
$injector = new FactoryDefault();
// defines the routes
$injector->setShared('router', function () {
return require_once('some/path/routes.php');
});
Then it the routes.php file:
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Router\Group as RouterGroup;
// instantiates the router
$router = new Router(false);
// defines routes for the 'users' controller
$user_routes = new RouterGroup(['controller' => 'users']);
$user_routes->setPrefix('/users');
$user_routes->addGet('/show/{id:[0-9]{1,9}}', ['action' => 'show']);
$router->mount($user_routes);
return $router;
Im defining routes in an alternate way, by defining routes groups. I find it to be more easy to organize routes by resource or controller.
2) When you enter the url example.com/users/show/123, the routes above will match this to the controller users and action show. This is specified by the chunks of code ['controller' => 'users'], setPrefix('/users') and '/show/{id:[0-9]{1,9}}', ['action' => 'show']
3) So now you create the controller. You create a file in, let's say, controllers/UsersController.php. And then you create its action; note the name that you used in the route (show) and the suffix of Action:
public function showAction(int $id) {
// ... do all you need to do...
// fetch data
$user = UserModel::findFirst(blah blah);
// pass data to view
$this->view->setVar('user', $user);
// Phalcon automatically calls the view; from the manual:
/*
Phalcon automatically passes the execution to the view component as soon as a particular
controller has completed its cycle. The view component will look in the views folder for
a folder named as the same name of the last controller executed and then for a file named
as the last action executed.
*/
// but in case you would need to specify a different one
$this->view->render('users', 'another_view');
}
There is much more stuff related to views; consult the manual.
Note that you will need to register such controller in the bootstrap file like (Im also including examples on how to register other things):
use Phalcon\Loader;
// registers namespaces and other classes
$loader = new Loader();
$loader->registerNamespaces([
'MyNameSpace\Controllers' => 'path/controllers/',
'MyNameSpace\Models' => 'path/models/',
'MyNameSpace\Views' => 'path/views/'
]);
$loader->register();
4) You will also need to register a few things for the views. In the bootstrap file
use Phalcon\Mvc\View;
$injector->setShared('view', function () {
$view = new View();
$view->setViewsDir('path/views/');
return $view;
});
And this, together with other things you will need to do, particularly in the bootstrap process, will get you started in sending requests to the controller and action/view defined in the routes.
Those were basic examples. There is much more that you will need to learn, because I only gave you a few pieces to get you started. So here are some links that can explain more. Remember, there are several different ways to achieve the same thing in Phalcon.
Bootstrapping:
https://docs.phalconphp.com/en/3.2/di
https://docs.phalconphp.com/en/3.2/loader
https://docs.phalconphp.com/en/3.2/dispatcher
Routing: https://docs.phalconphp.com/en/3.2/routing
Controllers: https://docs.phalconphp.com/en/3.2/controllers
More on Views (from registering to passing data to them, to templating and more): https://docs.phalconphp.com/en/3.2/views
And a simple tutorial to teach you some basic things: https://docs.phalconphp.com/en/3.2/tutorial-rest
The application begins with the routing stage. From there you grab the controller and action from the router, and feed it to the dispatcher. You set the view then call the execute the dispatcher so it access your controller's action. From there you create a new response object and set its contents equal to the view requests, and finally send the response to the client's browser -- both the content and the headers. It's a good idea to do this through Phalcon rather than echoing directly or using PHP's header(), so it's only done at the moment you call $response->send(); This is best practice because it allows you to create tests, such as in phpunit, so you can test for the existence of headers, or content, while moving off to the next response and header without actually sending anything so you can test stuff. Same idea with exit; in code, is best to avoid so you can write tests and move on to the next test without your tests aborting on the first test due to the existence of exit.
As far as how the Phalcon application works, and in what steps, it's much easier to follow the flow by looking at manual bootstrapping:
https://docs.phalconphp.com/en/3.2/application#manual-bootstrapping
At the heart of Phalcon is the DI, the Dependency Injection container. This allows you to create services, and store them on the DI so services can access each other. You can create your own services and store them under your own name on the DI, there's nothing special about the names used. However depending on the areas of Phalcon you used, certain services on the DI are assumed like "db" for interacting with your database. Note services can be set as either shared or not shared on the DI. Shared means it implements singleton and keeps the object alive for all calls afterwards. If you use getShared, it does a similar thing even if it wasn't initially a shared service. The getShared method is considered bad practice and the Phalcon team is talking about removing the method in future Phalcon versions. Please rely on setShared instead.
Regarding multiple views, you can start with $this->view->disable(); from within the controller. This allows you to disable a view so you don't get any content generated to begin with from within a controller so you can follow how views work from within controllers.
Phalcon assumes every controller has a matching view under /someController/someView followed by whatever extension you registered on the view, which defaults to .volt but can also be set to use .phtml or .php.
These two correspond to:
Phalcon\Mvc\View\Engine\Php and Phalcon\Mvc\View\Engine\Volt
Note that you DON'T specify the extension when looking for a template to render, Phalcon adds this for you
Phalcon also uses a root view template index.volt, if it exists, for all interactions with the view so you can use things like the same doctype for all responses, making your life easier.
Phalcon also offers you partials, so from within a view you can render a partial like breadcrumbs, or a header or footer which you'd otherwise be copy-pasting into each template. This allows you to manage all pages from the same template so you're not repeating yourself.
As far as which view class you use within Phalcon, there's two main choices:
Phalcon\Mvc\View and Phalcon\Mvc\View\Simple
While similar, Phalcon\Mvc\View gives you a multiple level hierarchy as described before with a main template, and a controller-action based template as well as some other fancy features. As far as Phalcon\Mvc\View\Simple, it's much more lightweight and is a single level.
You should be familiar with hierarchical rendering:
https://docs.phalconphp.com/en/3.2/views#hierarchical-rendering
The idea is with Phalcon\Mvc\View that you have a Main Layout (if this template exists) usually stored in /views/index.volt, which is used on every page so you can toss in your doctypes, the title (which you would set with a variable the view passed in), etc. You'd have a Controller Layout, which would be stored under /views/layouts.myController.volt and used for every action within a controller (if this template exists), finally you'd have the Action Layout which is used for the specific action of the controller in /views/myController/myAction.volt.
There are all types of ways you can break from Phalcon's default behavior. You can do the earlier stated $this->view->disable(); so you can do everything manually yourself so Phalcon doesn't assume anything about the view template. You can also use ->pick to pick which template to use if it's going to be different than the controller and action it's ran in.
You can also return a response object from within a controller and Phalcon will not try to render the templates and use the response object instead.
For example you might want to do:
return $this->response->redirect('index/index');
This would redirect the user's browser to said page. You could also do a forward instead which would be used internally within Phalcon to access a different controller and/or action.
You can config the directory the views are stored with setViewsDir. You can also do this from within the controller itself, or even within the view as late as you want, if you have some exceptions due to a goofy directory structure.
You can do things like use $this->view->setTemplateBefore('common') or $this->view->setTemplateAfter('common'); so you can have intermediate templates.
At the heart of the view hierarchy is <?php echo $this->getContent(); ?> or {{ content() }} if you're using Volt. Even if you're using Volt, it gets parsed by Phalcon and generates the PHP version with $this->getContent(), storing it in your /cache/ directory, before it is executed.
The idea with "template before" is that it's optional if you need another layer of hierarchy between your main template and your controller template. Same idea with "template after" etc. I would advise against using template before and after as they are confusing and partials are better suited for the task.
It all depends on how you want to organize your application structure.
Note you can also swap between your main template to another main template if you need to swap anything major. You could also just toss in an "if" statement into your main template to decide what to do based on some condition, etc.
With all that said, you should be able to read the documentation and make better sense of how to utilize it:
https://docs.phalconphp.com/en/3.2/api/Phalcon_Mvc_View

Symfony twig - Third party

i am currently working on a symfony project,
what i have:
app/Resources/views/mytemplate/
the folder mytemplate contains all of the important twig-views for my web app.
My question is, is there any possibility that third party members can create their own templates which override my "mytemplate" without creating controllers pointing to them ?
Like:
i have this template:
app/Resources/views/mytemplate/home/index.html.twig
An other person could create a new template in the same views directory like:
app/Resources/views/thirdparty/home/index.html.twig
to override my template.
is there any possibilty like this?
Greetings!
Well, to me, you have two possibilities :
The template that you want to be able to be redefined is the one specified with the method renderView() or similar in your controller : in this case, the possibilities are limitless. It's up to you to define the logic layer determining which template has to be rendered. You could for example force the user redefining the template to name it with a specific additional pattern, and then parse the right template to use thanks to a method inherited in all your controllers.
$content = $this->renderView(
$this->getInheritedTemplate('AcmeHelloBundle:Hello:index.html.twig'),
array('name' => $name)
);
The template that has to be redefined is one inherited in another twig template : In this case, it's almost the same. You could imagine writing your own Twig filter/function in order to retrieve the right template. The code should be very similar to the first case.
Hope this helped.

Dynamic Routing in cakephp issue

I want to use Dynamic Routing for the static pages of my site.
I have used the following code in my Routes file
$arr = ClassRegistry::init('Page');
and
$this->loadModel('Page');
$arr = $this->Page->find('all');
foreach($arr as $value)
{
//my code
}
But it doesn't work, and shows an error like below:
ClassRegistry is not defined
Don't do that
you've tried to put controller code in your routes file and are intending to make your site so needlessly dependent on the database. Of course, your whole site is likely dependent on the database, but by making your routes db-dependent all requests that make it to cakephp (which means, all requests that are not a static file in the webroot) need to talk to the db at least slowing things down, and if anything goes wrong with the db, your site is white page of fatal error awesomeness for all requests. This is because the routes file is loaded very early in the request handling process. The routes file is not supposed to contain any real logic - just Router::connect statements.
Alternative: Use a catchall route
If you have any pattern that you can use for your static pages, use it so that you have only one route definition. i.e.:
Router::connect('/x/*', array('controller' => 'some', 'action' => 'thing')); //eerily similar to the default static pages route
Alternative: Write a static routes file
Build, however you like, your routes logic whenever the rules for your routes change and write them to a static file. Therefore your routes.php file becomes:
<?php
... routes that don't change ...
require 'path/to/dynamic_routes_file.php';
You can use the afterSave handler for a relevant model to trigger rebuilding this dynamic routes file.
More alternatives
There are many other ways to handle this kind of thing e.g. override the error handling process to first check if there's one of these db-dependent routes to process - Or simply create a custom route class which implements literally whatever you want.
Whatever you do though - aim for the logic at run time to be as simple/cached/static as possible - don't build a system which makes all requests need to talk to the db all the time.

How to use different bootstraping for different modules in zend framework

I have two modules, default and mojo.
After the initial bootstraping code which is the same for both of the modules, I want, for example, to use different layouts for each module (Or use different credentials check etc).
Where do I put this: IF(module=='mojo') do this ELSE do that
If you are using Zend_Application (in ZF1.8) then you should be able to use the module specific configuration options to provide this functionality with a as explained in the relevant section in the documentation.
This would require you to set the layout in the config so it looked something like
mojo.resources.layout.layout = "mojo"
anothermodule.resources.layout.layout = "anotherlayout"
The layout would then be set automatically by the bootstrap.
The other alternative is to use a front controller plug-in that implements the preDispatch() method to set the layout based on the module name.
hmm i havent tried this
http://www.nabble.com/Quick-Guide-How-to-use-different-Layouts-for-each-module-to23443422.html#a24002073
the way i did that now was thru a front controller plugin
something like
switch ($request->getModuleName()) {
case "":
// set layout ...
}
I've looked into the subject a couple of days ago, trying to get it to work on bootstrap config alone. The big problem is that all the bootstrap files are loaded, so it gives some weird results in which layout is used.
My conclusion was that you can have the config in place, but you need to work with FrontController plugins or ActionController helpers. If you want to use config set in the application.ini and you want to load the config trough the bootstrap, helpers is the only way to go. From the helper, you can then load the ActionController and on that execute the getInvokeArgs to load the bootstrap. A lot of hastle... :)
Anyway, I've done a small implementation as an example in a blog post: http://blog.keppens.biz/2009/06/create-modular-application-with-zend.html
Goodluck,
Jeroen

Symfony: Is it possible to setTemplate for components?

There’s no setTemplate() for components! I know but maybe there is another way to do it ?
(The question seems to be about a php framework: http://www.symfony-project.org/)
There is no setTemplate method on sfComponents. You essentially have 3 options:
Name your component the same as the partial you'd like the component to render. This may not be possible if you have multiple components you'd like to share the same template.
Create a partial with the same name of your component and include the partial there. That is, if you had a component with an executeFoo() method that you wanted to render the _bar.php template, simply call include_partial('bar', $vars) inside of _foo.php.
Load the PartialHelper and render the partial manually inside of the components execute method and have the component return sfView::NONE.
Components don't handle templates, you can only use partials. If you need to return a specific partial from inside your components class you can do something like this:
return get_partial('module/action', array('paramName' => $paramValue));
Have a look into the symfony book, chapter 7 view layer
To get around this, i'm doing:
echo get_component('module', 'action', $this->getVarHolder()->getAll());
return sfView::NONE;
This worked for me:
$this->setVar('template', 'templateName');
Obviously the template have to be in the exactly same module.

Categories