I have a little problem, which I can't figure out by myself.
I created sort of a "webengine", which I build out of several classes.
The main-class, getting a "theme's" internals is called "Logic".
This logic-class includes all the files, needed for a website. I made it like that, so that every developer, creating such website could use function, that are given inside this class.
I now want to create a function, that allows these developers to include a CSS file. But this turns out to be quite difficult.
So far I tried this:
public function include_css($path_to_css) {
$path_to_css = $this->project_name . THEMES . "/" . ACTIVE_THEME . "/" . $path_to_css;
if(file_exists($path_to_css)) {
?>
<html>
<head>
<link rel="stylesheet" type="text/css" href=" <?php echo $path_to_css; ?>" />
</head>
<?php
} else {
return false;
}
}
/* Idea number 2 */
public function include_css($path_to_css) {
$path_to_css = $this->project_name . THEMES . "/" . ACTIVE_THEME . "/" . $path_to_css;
if(file_exists($path_to_css)) {
echo "
<html>
<head>
<link rel='stylesheet' type='text/css' href='".$path_to_css."' />
</head>
";
} else {
return false;
}
}
Please note that unclarified attributes are declared in a complex matter, so it would be a very long post, if I would paste these here.
I am just getting this console error: http://127.0.0.1/vpm2/themes/numberOne/css/test.css 404 (Not Found), which means there is no such file. The interesting thing about that, is, that this is the exact path to the right file!
Is there anything I am missing?
I found the solution. Apparently the CSS Path seems to be wrong. It needs to look like that:
$path_to_css = THEMES . "/" . ACTIVE_THEME . "/" . $path_to_css;
So the result looks like that:
themes/numberOne/test.css
Before it looked like that:
/vpm2/themes/numberOne/test.css
Related
I would like to order nicely the head section of a joomla site. After search of the forums I have come across this one http://forum.joomla.org/viewtopic.php?f=642&t=671526&p=3283757#p3283757
There a nice suggestion is to copy the /renderer/head.php file into the template folder and alter it to current needs.
They suggest
Blockquote
The render function in head.php not uses the $name var, so it`s fine to use to separate the js and metatags with css files and use the jdoc statement like this:
jdoc:include type="head" name="head" <-- will include all exept js (into
the head section)
jdoc:include type="head" name="foot" <-- for the js (before body tag closes)
Blockquote
But I simply have no idea how to implement this.
HAve someone experience with editing head.php in Joomla? I would appreciate any help.
I investigated a little bit about it and it seems a little bit hacky to do it.
This solution is currently working on Joomla 3.*.
First of all you have to modify /librabies/joomla/document/document.php.
Once you are in there update the function loadRenderer() from this:
public function loadRenderer($type)
{
$class = 'JDocumentRenderer' . $type;
if (!class_exists($class))
{
$path = __DIR__ . '/' . $this->_type . '/renderer/' . $type . '.php';
if (file_exists($path))
{
require_once $path;
}
else
{
throw new RuntimeException('Unable to load renderer class', 500);
}
}
if (!class_exists($class))
{
return null;
}
$instance = new $class($this);
return $instance;
}
To this :
public function loadRenderer($type)
{
$class = 'JDocumentRenderer' . $type;
if (!class_exists($class))
{
$path = __DIR__ . '/' . $this->_type . '/renderer/' . $type . '.php';
$app = JFactory::getApplication('site');
$path_custom = JPATH_THEMES . '/' . $app->getTemplate() .'/html/renderer/' . $type . '.php';
if (file_exists($path_custom))
{
require_once $path_custom;
}
elseif (file_exists($path))
{
require_once $path;
}
else
{
throw new RuntimeException('Unable to load renderer class', 500);
}
}
if (!class_exists($class))
{
return null;
}
$instance = new $class($this);
return $instance;
}
Actually the new code is looking for a render file in your template directory.
Now you are allow to copy libraries/joomla/document/html/renderer/head.php to templates/TEMPLATE_NAME/html/renderer/head.php and modify it.
If you want to use those :
<jdoc:include type="head" name="head" />
<jdoc:include type="head" name="foot" />
Update templates/TEMPLATE_NAME/html/renderer/head.php to this version here.
Another option (for joomla 2.5/3.0 and with slightly adjustments joomla 3.5.x) as mention here is the following:
1.) grap the "/libraries/joomla/document/html/renderer/head.php" from a Joomla 3.0 installation ZIP file
2.) rename that to "head_renderer.php" and put that into your template folder
3.) in your template index.php add:
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'head_renderer.php';
4.) If you are still using Joomla 3.0 you are fine, if you are using Joomla 3.5 edit head_renderer.php and change JDocumentRendererHead to JDocumentRendererHtmlHead.
5.) Adjust the head_renderer.php so that it fits your requirements
I have a directory structure like this:
www/
index.php
my-library/
my-library.php
assets/
my-library.css
images/
loading.gif
I need my-library.php to inject stylesheets into index.php. To do so, I need to get the relative path from index.php to my-library/ -- which in this particular case, would simply be "my-library".
From within my-library.php, is it possible for me to acquire this relative path?
Or must index.php supply it, with something like the following?
<?php
require "my-library/my-library.php";
$mlib->linkroot='my-library';
?>
To clarify, below I have included a more detailed representation of what I'm trying to do:
index.php:
<?php require "my-library/my-library.php"; ?>
<!doctype html>
<head>
<title>Testing My Library</title>
<?php $mlib->injectAssets(); ?>
</head>
<body>..</body>
my-library.php:
<?php
class MyLibrary(){
public $rootpath;
public $linkroot;
function __construct(){
$this->rootpath= __DIR__; // absolute path to my library's root directory (for serverside use)
$this->linkroot = "???"; // relative path to my library's root from index.php (for clientside use, like linking in stylesheets)
}
function injectAssets(){
$csslink = $this->linkroot.'/assets/my-library.css';
echo '<link href="'.$csslink.'" rel="stylesheet" />';
}
}
$mlib = new MyLibrary();
?>
The line I'm interested in figuring out, would be $this->linkroot = "???";.
I'm practically trying to acquire the string that was used to include/require the current script.
I got it! I only had to build a Rube Goldberg Machine to do it!
Thanks PHP.
$linkroot = ascertainLinkroot();
function ascertainLinkroot(){
return makeRelativePath(
getTopScriptPath(),
__DIR__
);
}
function getTopScriptPath(){
$backtrace = debug_backtrace(
defined( "DEBUG_BACKTRACE_IGNORE_ARGS")
?DEBUG_BACKTRACE_IGNORE_ARGS
:FALSE );
$top_frame = array_pop($backtrace);
$top_script_path = $top_frame['file'];
return $top_script_path;
}
function makeRelativePath($from,$to){
// Compatibility
$from = is_dir($from) ?rtrim($from,'\/').'/' :$from;
$to = is_dir($to) ?rtrim($to,'\/').'/' :$to;
$from = str_replace('\\','/',$from);
$to = str_replace('\\','/',$to);
//----------------------------
$from = explode('/',$from);
$to = explode('/',$to);
$path = $to;
foreach($from as $depth => $dir) {
if ($dir === $to[$depth]) { // find first non-matching dir
array_shift($path); // ignore it
} else {
$remaining = count($from)-$depth; // get number of remaining dirs to $from
if ($remaining>1){
// add traversals up to first matching dir
$padLength = -(count($path)+$remaining-1);
$path = array_pad($path, $padLength, '..');
break;
} else {
$path[0] = './'.$path[0];
}
}
}
return rtrim(implode('/', $path),'\/');
}
So, basically, I use the makeRelativePath function to calculate a relative path from the top script's absolute path to the current script's absolute directory path (__DIR__).
I realized that I'm actually looking for the relative path to the library from the top script, not just the parent script -- because the top script is the one where clientside assets will need to be referenced in relation to.
Naturally, PHP doesn't just give you the top script's absolute path. On some environments, the top script's path can be available as a $_SERVER variable, however environment independence is important for me, so I had to find a way.
getTopScriptPath was my solution, as it uses debug_backtrace to find it (creepy, I know), but it is the only environment-independent way to fetch it (to my knowledge).
Still hoping for a more elegant solution, but am satisfied that this one works.
I believe this is what you're looking for:
$this->linkroot = basename(pathinfo($_SERVER['REQUEST_URI'], PATHINFO_DIRNAME));
You can remove basename() to get the full path. Basically, you can run the following code:
echo '<pre>';
var_dump($_SERVER);
echo '</pre>';
If the path you're looking for isn't there in some shape or form, then it simply isn't available and you will have no other choice but to hard code it, or at least hard code part of it.
Have you tried doing a relative link from the root? If not, you might try something like this, if I understand your folder structure.
<link href="/my-library/assets/my-library.css" rel="stylesheet" type="text/css" />
Links like this in any page within your site will pull the same stylesheet, up or down the site structure.
I am trying to fetch my CSS from external CDN service let's say http://cdn.example.com/.
This code is suppose to check if file exists on external CDN and if it does, then get that file else get it from a local folder.
Currently this is fetching only the local copy even though the file exists on external CDN.
Please help me correct this code.
function getCSSfile($filename)
{
$externalcss = EXTERNAL_CDN.'css/'.$filename.'.css';
$localcss = LOCAL_CDN.'css/'.$filename.'.css';
$ctx = stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
));
if (file_get_contents($externalcss, false, $ctx) !== false) {
echo '<link href="' . $externalcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else if (file_exists($localcss)) {
echo '<link href="' . $localcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else {
echo 'Error loading CSS File';
}
}
UPDATE:
Updated the code as per #DaveRandom's suggestion. Currently code runs fine it fetches the copy from external CDN but if the external CDN is unavailable it does fetches the local copy BUT throws the following error too:
Warning: file_get_contents(http://cdn.localtest.com/css/core.css): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in D:\xampp\htdocs\localtest2\core\core.php on line 165
and in line 165 this is the code
if (file_get_contents($externalcss, false, $ctx) !== false) {
I am testing it locally and created some domains on my XAMPP Server, hence cannot share a live link.
I don't believe you can use file_exists on a URL, this answer might shed some light on the code you could use to properly check in the URL returned a file to you.
But to summarize, you want to check the status code that is returned to you, rather than using file_exists.
The problem with checking if the file can be accessed through PHP is that the check is done from your server, not the client loading the files. Just because your server can access the CSS file from the CDN does not mean the client can.
If you are going to do a check with a fallback, it is safer to do it on the client side using javascript.
How to fallback to local stylesheet if CDN fails
Another potential problem (in addition to #Johannes' answer) would be your constants. In the question you structured your CDN URL as http://cdn.example.com. Appending this to css/ (as in your code) would produce http://cdn.example.comcss/, which isn't a valid URL.
Make sure that the constants (base URL's) are structured as http://cdn.example.com/.
Edit: To add to #Johannes' answer, I found this link from another answer on SO: http://www.php.net/manual/en/function.file-exists.php#75064
To put the code here:
$file = 'http://www.domain.com/somefile.jpg';
$file_headers = #get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
$exists = false;
}
else {
$exists = true;
}
The way I look at this, you have this process the wrong way round - you should serve your local copy if it exists (and is not stale, a mechanism which needs to be defined) and fall back to the CDN. This means you are behaving like a cache.
But to answer the question directly, your best bet would be to use a HEAD request to the CDN to see whether it exists. It's tempting to use get_headers() for this, but actually this causes a GET method request unless you alter the default stream context - this creates potentially unwanted global state in your application.
So my preferred approach would be to create localised stream context and use it in conjuction with a function that will accept it as an argument. For the sake of simplicity, in the below example I'll use file_get_contents().
function getCSSfile($filename)
{
$externalcss = EXTERNAL_CDN.'css/'.$filename.'.css';
$localcss = LOCAL_CDN.'css/'.$filename.'.css';
$ctx = stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
));
if (file_get_contents($externalcss, false, $ctx) !== false) {
echo '<link href="' . $externalcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else if (file_exists($localcss)) {
echo '<link href="' . $localcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else {
echo 'Error loading CSS File';
}
}
Now, this is not perfect by a long way, but I've recycled a lot of mechanism from your original code. There is still global state (the use of user-defined constants in functions like this is a BIG no-no for me) and you still have a function which produces output directly instead of returning control to the caller.
I would prefer to pass $externalcss and $localcss in as arguments, and simply return the chosen URL string instead of formatting it into HTML and echoing it. This way, the code is isolated and doesn't rely on anything external, and by returning the string you allow the caller to further manipulate the data if necessary. In essence, it makes the code infinitely more re-usable.
Side note: Defining functions within functions, while possible, isn't recommended. This is because the second call will cause a Cannot redeclare function fatal error.
Okay since the error solution was not explained by anyone... I decided to answer my own question. This is the solution I found:
function getCSSfile($filename)
{
$externalcss = EXTERNAL_CDN.'css/'.$filename.'.css';
$localcss = LOCAL_CDN.'css/'.$filename.'.css';
$ctx = stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
));
if (#file_get_contents($externalcss, false, $ctx) !== false) {
echo '<link href="' . $externalcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else if (file_exists($localcss)) {
echo '<link href="' . $localcss . '" rel="stylesheet" type="text/css" media="all"/>';
} else {
echo 'Error loading CSS File';
}
}
As suggested by Mark B
As stated in the docs, file_get_contents() will throw a warning if the stated resource cannot be found.
This is one of the few cases in which using the # error suppression operator may be justified, e.g.
if (#file_get_contents($externalcss, false, $ctx) !== false)
to prevent the warning from mucking up the output.
I have modules for category:
+modules/
+category/
+assets/
+css/
+js/
+images/
+components/
+controllers/
+models/
+views/
-CategoryModule.php
What is the best way to includes the css and jss to all views?
Publish and register in CategoryModule init method - this will make available your css and js in category module.
Something like this:
public function init() {
$path = $this->assetManager->publish(Yii::getPathOfAlias('application.modules.category.assets'));
$this->clientScript->registerCssFile($path . '/css/some-css.css', 'screen, projection');
$this->clientScript->registerScriptFile($path . '/js/some-js.js');
}
create module layout file under views/layout and call it in module config file as
$this->layoutPath = Yii::getPathOfAlias('application.modules.moduleName.views.layouts');
$this->layout = '/layouts/layoutname';
register all the js and css file as #PeterM mentioned
Create a folder "layouts" in your views folder. Create main.php in that layouts folder.
In your , add following code:
<link rel="stylesheet" href="<?php echo Yii::app()->request->baseUrl; ?>/css/style.css" type="text/css" media="screen"/>
<script type="text/javascript" src="<?php echo Yii::app()->request->baseUrl; ?>/js/cycle.js"></script>
This is your default layout. So add,
<?php echo $content; ?>
This is another method to include css and js in all views.
Easy using this static method
<?php Yii::app()->clientScript->registerCssFile(Yii::getPathOfAlias('application.modules.curriculo.assets') . '/bootstrap/datepicker/css/datepicker.css'); ?>
<?php Yii::app()->clientScript->registerScriptFile(Yii::getPathOfAlias('application.modules.curriculo.assets') . '/bootstrap/datepicker/js/bootstrap-datepicker.js'); ?>
This should help you:
http://www.yiiframework.com/wiki/249/understanding-the-view-rendering-flow/
All three sections (beginContent, container and endContent) are explained in detail.
I'm trying to load the google maps API ie:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true">
in my head template. But because I've only got one page with a google map on it (I'd rather not have the API load for all files), how would I send the message from the controller through to the view that I wish to load this particular JS file?
Thanks for your help.
CodeIgniter has a segments class. You would be able to run some code like:
<?php if($this->uri->segment(1) == 'map') { ?>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true">
<?php } ?>
When on page http://yoursite.com/map/ it will load the script.
One solution is to either use a template library that has javascript/css "injection" - see:
http://williamsconcepts.com/ci/codeigniter/libraries/template/reference.html#utilities
$this->template->add_js('js/jquery.js');
$this->template->add_js('alert("Hello!");', 'embed');
for more information.
If you don't want to use a template library, do something like this:
*assuming on the "Map" controller, and that you need the JS file on the default page.
class Map extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
$scripts = array(
'<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true">' . "\n",
'<script>something</script>');
/* this method lets you add multiple...*/
$data['scripts'] = $scripts;
$this->load->view('my_map/index', $data);
}
}
in your view:
if(isset($scripts))
{
foreach($scripts as $script)
{
echo $script;
}
}
essentially you build an array of script files/css files (whatever), then check for its prescence and dump it in the head section of your view.
I'd personally go for the template option.
Also note CI2.0 has a new javascript driver might be worth a read
<?php
/**
* Head files loader
* #author azhar
**/
function headscripts($path)
{
if(is_string($path))
{
echo "<script type='text/javascript' src='". base_url($path) ."'></script>\n";
}elseif(is_array ($path)){
foreach ($path as $p) {
echo "<script type='text/javascript' src='". base_url($p) ."'></script>\n";
}
}
}
function headlinks($path)
{
if(is_string($path))
{
echo "<link rel='stylesheet' href='". base_url($path) ."'/>\n";
}elseif(is_array ($path)){
foreach ($path as $p) {
echo "<link rel='stylesheet' href='". base_url($p) ."'/>\n";
}
}
}
?>
Add this file in your helper_directory under the name head_helper. In your controller inside an action use this code
$data['headscripts'] = array('js/main.js');
And in your view file use this function
headscripts($headscripts);
For stylesheet use this
headlinks($headlinks);
And yes do not forget to load the helper using autoload.php file in config folder like this
$autoload['helper'] = array('url', 'file','head');
Thanks for your answers guys, I ended up doing a mixture of Ross and leaf dev's suggestions before I found your answers here, so I guess I was on the right track.
My controller has:
$data['head'] = array('specificjs');
$this->load->view('view',$data);`
and my view has:
if(isset($head)){
foreach($head as $item){
$this->load->view('js/'.$item);
}
}
and my 'specificjs' view has what's required.
This way I can load as many custom scripts as I want and have the code in a view not a controller.
Thanks again, but keep any further suggestions coming!
write a helper for this. Pass the scripts names in an array and inside the helper function iterate over them and print the scripts