I'm almost done writing a very simple module for zf2. One thing I'd like my module to do is to inject some css to the layout so that the HTML it generates displays in a nicer way.
Is this possible to do from within a module? If so, how?
EDIT: Thank you all for the prompt responses. However I think I probably didn't explain myself very clearly. When I say "inject some css" I mean taking a string of css and having it actually rendered INSIDE the layout. I didn't mean linking to an external css file or having an asset manager publish my files like the answers so far have suggested.
See Publishing assets from modules in Zend Framework 2 or How to merge Zend Framework 2 module public directories for discussion of the options you have for pushing public assets from a module.
And in addition to pushing your module assets to public, you could put the append into a triggered method like onBootstrap:
public function onBootstrap($e) {
$sm = $e->getApplication()->getServiceManager();
$headLink = $sm->get('viewhelpermanager')->get('headLink');
$headLink->appendStylesheet('/assets/MyModule/css/mystylesheet.css');
}
Try to use something like:
$sm = $this->getEvent()->getApplication()->getServiceManager();
$helper = $sm->get('viewhelpermanager')->get('headLink');
$helper->prependStylesheet('/css/mystylesheet.css');
in Your module controller.
EDIT:
If you want to store css style in module, You can either render it in Your layout file (head section) or, the better way, create another route in module, for example /get/style/[:name]. This route point to another action which returns only plain text/css document. More or less :)
Add a variable to your layout for where you'd like the CSS to be inserted:
Some Link
Then in your Controller, load and assign it however you'd like:
$this->layout()->CSS = "CSS";
$this->layout()->CSS = $this->getRequest()->getPost('CSStoInject');
$this->layout()->CSS = fopen(), curl(), etc.
Related
I am new to PHP, trying to understand how to use a simple template system with PHP, I like "Plates", mainly because it claims to be a template system, not a template language, but the documentation is kind of confusing.
As an example where this code "controller" leaves? Is it a another PHP file?
// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');
// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);
Shouldn't this code "profile.php" call the controller file somewhere?
profile.php
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>
The template file:
template.php
<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>
Does anyone have a better code sample using "Plates" in PHP where I can see how this template system works?
Thank you!
The example in the Plates doc is pretty good and simple. The way I see it - you might have an MVC controller or you might not; the code in question may reside in a simple script (lets say index.php for the sake of clarity). Lets imagine the site structure looks like:
/index.php
/templates/ folder
/templates/profile.php
/templates/template.php
The code in index.php becomes:
// Create new Plates instance
$templates = new League\Plates\Engine('/templates');
// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);
You might have it in an MVC controller, but that is totally different topic.
I wanted to try a pure php templating engine too so I tried out Plates as well. It is simple. I like simple solutions for simple problems. They are faster to implement.
If you are new to php using Plates can be a great way to start to write 'cleaner' code with very little additional investment of your time.
Because you are new to PHP there is a bit of background detail you need to understand first. Then I think it will be clear.
The example here is not so great in that the paths are not that useful. Assume they intend to show that the fully qualified path is required. A better example would have used something like:
$templates = new Engine(__DIR__ . '/templates');
where the templates directory is a sub-directory of the current folder that the presenter or controller may be in.
Since templates are central to presentation, it is my opinion that presenter is a better name for the class that will be using the templates but a lot of people use controller because of the popularity of mvc.
"\League\Plates\Engine" is a namespace, not a path. You can include a "use" statement in your class for every imported class you want to use from that namespace if you want.
On their "installation" page here they show that you have to edit the composer.json file to load plates. If you are unfamiliar with composer all you have to do is install it and run "composer update" in the folder with the composer.json file from the installation page and it will create the vendor folder for you with all the supporting files necessary to run Plates. It will place these files in a vendor folder which is why you need to require vendor/autoload.php.
Plates also assumes that the files in your template directory are php files and that is why they don't require a file extension on the parameter. so 'template' and 'profile' refer directly to the template.php and profile.php files.
The essential idea behind templating is to separate your view and code. Data is obtained by the code and passed into the view. These template files represent the view and the data is passed into the templates via the associative array in the render function in the example.
Because Plates is a php based templating engine, the templates ARE php files. So some php coding will be required to obtain the data from the model (the associative array) and for looping constructs and such. What you want to achieve is to keep the code specific to only what is necessary to render the data in the html and nothing else.
The profile.php page and the template.php page are both "templates" The template.php file is useful if you are going to display a whole page but unnecessary if you just want to output an html element. In the latter case the profile.php file in the example could be produced without the optional page 'layout'.
So what the 'render' function basically does is to load the php file specified by name and insert all the data from the associative array into that file according to its own code and optionally its associated layout template file and return the resulting html.
The class using the templates let's call it Presenter.php should have code something like this in it:
<?php
require 'vendor/autoload.php';
use \League\Plates\Engine;
class Presenter {
private $name;
function __construct($name){
$this->name = $name;
}
function render() {
$templates = new Engine(__DIR__ . '/templates');
echo $templates->render('profile', ['name' => $this->name]);
}
}
and an index.php like this:
<?php
require(__DIR__ . '/Presenter.php');
$presenter = new Presenter('Jonathan');
$presenter->render();
...
where your file structure in your project directory looks something like this:
index.php
Presenter.php
templates/template.php
templates/profile.php
composer.json
composer.lock
vendor/...
That should get anyone interested in trying Plates started.
Ok,
So quick question that is driving me crazy with FuelPHP
For css, js, and img assets I can do this in a view
<?php echo Asset::css('main.css'); ?>
But if I try to add a folder - for example - "media" to the public/assets directory I can not do this:
<?php echo Asset::media('myvideo.mp4'); ?>
Does anyone know if there is a way to configure that kind of functionality? Has anyone been able to modify the asset class to do that?
Thank you very much for your time and help!
I don't know if there is such fashion that you could create your own static method name (the one you like is media as I haven't tried it yet). But you declare that path instead. Consider this example:
(file is in public/assets/media/file.mp4)
Controller
Asset::add_path('assets/media/', 'media');
View
Video 1
You can easily create such methods by extending the core class.
This can not be solved generically (for example with a magic __call()), because the class would not know which HTML to generate for "media" (or whatever you want to add).
I am trying to give a shot to HMVC in Codeigniter. Here is my folder structure.
-ROOT
--APPLICATION
---MODULES
----Module_Email
-----Controllers
-----Models
-----Views
-----Assets
------JS
------CSS
------IMG
To render the Module i have to use
Module::run('Module_Email');
This method will output the rendered output, an example is given below
<script type="text/javascript" src="PATH/TO/EMAIL_MODULE/JS/JS_FILE.JS"></script>
<div data-module-name="Module_Email" class="Email_wrapper">
//RENDERED HTML CONTENT
</div>
Now here my problem start. Normally i would like to put all my resources to header. So when i call any module, its dependence need to be added in header instead of from where its get called.
I searched a lot but i couldn't find any good methods.
Please help.
Update
Currently i have a function on my header called get_assets() which will output predefined resources to header. But i cant say which modules is going to use in pages, so the system need to check which modules are used in this page, and if its used then its dependencies need to be added on header.
Seems like your main problem then is trying to figure out what modules were used.
Unfortunately as far as I can tell with the default Wiredesignz modular extension there is no way to access the module name unless you write some sort of hack to get at that data. The module being used is stored in the protected variable $module in the MX_Router class, however, there is no public method to allow you to get access to it. So your only choice would be to extend the class and create a public function.
Alternatively you could use a forked version of Wiredesignz implementation which I did which provides numerous other features including a public function to get at the $module variable. Using the forked version I wrote you could then use code such as this:
<?php $module_name = $this->router->fetch_module(); ?>
However, that will only record the last module you loaded, so you would still need to do work to store all the modules, and then have your function use this information to determine what assets to load. If I were doing something like you I would probably fork my version and then create an additional data structure to store every module that was loaded that you could then later get access to.
I don't think this is exactly what you were hoping for, but might be something to get you on the right track to finding a solution.
I added an array to the Module class to store the assets and two functions to store/retrieve the items. Here is the source (updated Modules.php)
# Register your assets
public static function register_asset( $asset )
{
if( in_array($asset,self::$assets) === FALSE )
{
self::$assets[] = $asset;
}
}
public static function assets()
{
return self::$assets;
}
and now you can register your assets like this inside your module
Modules::register_asset('myslider.js');
You can retrieve all your assets using
Modules:assets();
Which will return an array of assets that can be processed depending up on the situation.
I know there are several similar topics around but I read and tried most of them but still can't figure out how to do this.
I have a written a component in Joomla 2.5 and it works so far. I have different views and I can load the views using the controller.php.
One of the views shows a table out of my data base (data about teams).
Now I'd like to have another layout of the same view which would display the data base table as a form so can change the content.
That's the file structure:
views/
- teams/
- - tmpl/
- - - default.php
- - - modify.php
- - view.html.php
That's out of the view.html.php file:
...
// Overwriting JView display method
function display($tpl = null) {
...
$this->setLayout('modify');
echo $this->getLayout();
// Display the view
parent::display($tpl);
}
I tried different combinations of setLayout, $tpl = ..., default_modify.php, etc.
but I always either get the default layout or some error like 'can't find layout modify'
I load the site with .../index.php?option=com_test&task=updateTeams
And the controller.php looks like this:
function updateTeams(){
$model = $this->getModel('teams');
$view = $this->getView('teams','html');
$view->setModel($model);
$view->display();
}
I had a similar problem, I created some kind of user profile view and wanted them to be able to edit the fields without having to create a new model for it (would have similar functions, hate redundancy...). What worked for me is to simply call the layout like this:
index.php?option=com_mycomponent&view=myview&layout=edit ("edit" would be "modify" in your case)
To do this I didn't touch the view.html.php (well I did at first but I didn't have to.). And you don't need to use the controller either. If you want to load the modify view, just add a button to your regular view linking to the modify layout. No need to change anything else.
I happen to have written a blog article about it, check it out if you want: http://violetfortytwo.blogspot.de/2012/11/joomla-25-multiple-views-one-model.html
Hope this helps.
Ok this is the problem .. you don't want another layout, you want a new MVC triad that is based on forms rather than rendering. So if you look at any of the core content components you will see in the backend they have a mvc for say ... contacts and one for contact and contact is the editor. If in the front end you will notice that com_content and com_weblinks have mvc for artice/weblink and then separate ones for editing.
You need a really different model and layout and set of actions for editng than for just rendering.
Old topic, but it might still help.
It seems that when one wants to change the layout, the $tpl must not be included in the display() or must be null.
So the previous code would be:
function display($tpl = null) {
/* ... */
$this->setLayout('modify');
// Display the view without the $tpl (or be sure it is null)
parent::display();
}
Situation: only main page is accessible by default, all other pages needs a logged in user. When a module is loaded without user, a login template should be displayed, and no module. In other words, the $sf_content must be emptied in layout.php which is not 100% ok since there is logic in the layout. Is there elegant way for that? I dont think a helper is OK either....
Check out security filters, this is one standard way security is designed in symfony.
You even can implement your own SecurityFilter class with the functionality you want.
http://symfony.com/legacy/doc/reference/1_4/en/12-Filters#chapter_12_security
It is done by default for you by the sfBasicSecurityFilter filter. You just need a good configuration. Read this part of the Jobeet tutorial. You should use sfDoctrineGuardPlugin (or sfGuardPlugin if you using propell) for user authentication.
To complete my comments above: There are different ways to override the layout. You could use the methods:
setLayout($name)
//or using foward, which forwards current action to a new one (without browser redirection)
forward($module, $action);
inside your action class. In case you wand to modify the layout inside a filter, you can use something simular to this:
class yourFilter extends sfFilter {
public function execute($filterChain) {
if($yourConditionForOverrideTheDefaultLayout) {
//here the syntax to change the layout from the filer
$actionStack = $this->getContext()->getActionStack();
$actionStack->getFirstEntry()->getActionInstance()->setLayout('yourLayout');
}
$filterChain->execute();
}
}
To avoid unnecessary duplication in the layout file you can work with Fragments and Partials.