Failed to load css files - cakephp

After setting up a fresh copy of CakePHP project, the css reference from the code is:
/my_app_name/css/cake.css
While the real location of my css files is:
/my_app_name/webroot/css/cake.css
Why is that?

Why is that?
CakePHP, as with most frameworks, makes use of url rewriting by default (not a requirement, it can also be turned off). For apache users this is implemented via .htaccess files, such as this one in the root of your application:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
</IfModule>
And another in the webroot - the presence of these files mean url rewriting just-works for the majority of users.
The rules in the application root folder rewrite all requests to the webroot folder, thus these urls are actually equivalent:
http://localhost/my_app_name/some/file.css
http://localhost/my_app_name/webroot/some/file.css
The primary purpose of these rewrite rules is security - it prevents the possibility of accessing application files outside the webroot folder - something which is not necessary if using a production install. A side effect of this is that urls remain the same whether it's a development-style or production-style install.
Use helper classes
Classes such as the html helper take care of knowing where files are and linking to them appropriately, don't be tempted to hardcode the path to your assets in your template files i.e. don't do this:
<html>
<link rel="stylesheet" href="/my_app_name/css/cake.css" />
instead do this:
<html>
<?= $this->Html->css('forms'); ?>
Otherwise, you'll find that even something as simple as renaming your application mean links/assets break.

If your CSS files are located in /app/webroot/css/ (what is default location) you don't have to know nothing else, include them in your template absolute to webroot:
<link href="/css/cake.css" rel="stylesheet" type="text/css">

Related

CodeIgniter3 - routes do not work when serving app as example.com/codeigniter

I have an application based on codeigniter3 framework hosted on VM bitnami lampstack. Initially I have set up the apache to serve the application from the root domain: example.com/. Furthermore I have an .htaccess file for removing the index.php from url as per CI3 documentation.
The content of my .htaccess is as follows:
RewriteEngine on
RewriteCond $1 !^(index\.php|assets|static|vendor|images|js|css|uploads|favicon.png)
RewriteCond %(REQUEST_FILENAME) !-f
RewriteCond %(REQUEST_FILENAME) !-d
RewriteRule ^(.*)$ index.php/$1 [L]
Recently I have changed the apache configuration as such that the application to be served from example.com/codeigniter and although the main page is loading correctly all the links in application are broken and when clicked they return not found message: The requested URL /about was not found on this server.
My routes in config/routes.php looks like this:
##---------------- Home Routes ------------------##
$route['about'] = 'home/about';
$route['login'] = 'home/login';
The link in the navbar is set like this:
<li class="navbar-item" role="presentation">
<a class="navbar-link" href="/about">
<i class="far fa-address-card"></i> About
</a>
</li>
When the link is clicked it is pointing to example.com/about instead of example.com/codeigniter/about. But even if I add as href="/codeigniter/about"it is still does not work. Seems to me that the somehow the codeigniter fails to map the path to the correct controller.
The problem is solved in part by adding index.php before the route (e.g. example.com/codeigniter/index.php/about). It is loading the correct page but fails to load the static files (css, js and images files).
So seems to me that problem results from .htaccess file but I do not know how to fix it. What should I add to or remove from that file?
Do you have any ideea how this problem may be solved?
Thanks!

CakePHP themed with robots.txt

I have a CakePHP application that uses themed views, css and images. Now I need to have themed robots.txt as well.
Naturally I put a robots.txt file in every theme folder /View/Themed/Theme/webroot/robots.txt, but only the one in the app/webroot gets displayed. Usually themed files (img,css,js,ctp) will overwrite the "default" files.
Is there a way to have different robots.txt files?
note: before I used to have something like this in the htaccess file
RewriteCond %{HTTP_HOST} ^bla.website.de$
RewriteRule robots.txt bla.robots.txt [L]
RewriteCond %{HTTP_HOST} ^foo.website.de$
RewriteRule robots.txt foo.robots.txt [L]
RewriteCond %{HTTP_HOST} !^www.website.de$
RewriteRule robots.txt noindex.robots.txt [L]
But this will get out of hand very fast.
Themes don't work like that
Usually themed files (img,css,js,ctp) will overwrite the "default" files.
Actually, that's not the case. CakePHP can only handle requests that reach the php code, if there is a static file matching the path in the way, that will get served directly by the webserver, as that's what the default rewrite rules implement.
When using a theme CakePHP will change the requested url i.e.:
app/Plugin/DebugKit/webroot/js/my_file.js becomes app/webroot/debug_kit/js/my_file.js
app/View/Themed/Navy/webroot/css/navy.css becomes app/webroot/theme/Navy/css/navy.css
So it is not that the response for assets (/css/somefile.css) is modified, an entirely different request (/using_this_theme/css/somefile.css) is made when using a theme.
This is, in fact, something you're expected to take advantage of, by putting or linking your theme assets directly in the webroot as serving files via php is slower than not invoking php.
Use a route and a controller action, not rewrite rules
Since you have a multiple-domain-points-at-one-application setup (implied) and want a single url (/robots.txt) to return different content it's not possible with the default rewrite rules to make the url point at a static file1. To make the contents of /robots.txt dynamic, simply delete the file in webroot/robots.txt and add a route and controller action to handle serving the content based on the theme that's relevant to the request.
1 Obviously it is possible to do it by changing rewrite rules, but that means added complexity, and prevents the response being configurable (using a different theme -> instant change of content). You could consider generating your rewrite rules programatically though

locationProvider html5mode is not working

I m using modularized routes and I want to remove the # tag from my URL. But as most articles says I added this code into my route
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.otherwise({
redirectTo: '/'
});
// use the HTML5 History API
$locationProvider.html5Mode(true);
})
and I added this to my master page(index.html)
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
<!-- build:css(.) styles/vendor.css -->
<!-- bower:css -->
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
<!-- endbower -->
<!-- endbuild -->
<!-- build:css(.tmp) styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
<base href="/">
</head>
and I added base tag too. But the problem is when I enter the url like this
https://localhost:9000/loginselect
it says
Cannot GET /loginselect
But if I enter this as below(as previus) its working
https://localhost:9000/#/loginselect
but it shows the Url as
https://localhost:9000/loginselect
but when I refresh again the same error occurs. Could any one help me. I m using requireJs for loading files and modularized route files are loading using requireJs
You need to configure your server to serve index.html on that path.
html5Mode only sets Angulars behaviour when it comes to non-fragmented urls, but Angular only handles things -after- the first request, since on the first request the page and the javascript has not even loaded yet. The first request always hits the server, so when you enter the url https://localhost:9000/loginselect directly a request will be sent to the server, and if the server doesn't recognise the url you will get an error.
To solve this you need to configure your server to server your index.html file for that url, and for any other url your app uses. Typically you will set the server to sent index.html on any url except for those matching static assets, like images. If you do that, then on these urls the server will load index.html, Angular will start, and Angular will handle the route.
The reason it works for https://localhost:9000/#/loginselect is that by convention servers will ignore the fragment part of the url, i.e. '#/loginselect`. So the server grabs whatever is on / (since it ignores the rest) which is probably index.html. Angular then kicks in and handles the fragment part.
Edit:
To do this in nginx I would use something like this:
location / {
index index.html;
try_files $uri $uri/ /index.html =404;
}
This checks if there is a file on the path given (so if you ask for a static resource like an image it will give you that) and if it can't find one it will serve index.html instead.
Note that this is the simplest possible case and it has the drawback of serving your index.html on ANY 404. You could also be more specific and exclude certain directories (like /assets or /static) instead of doing a try_files. Then you could still have a 404 if you try to get a static asset that doesn't exist.
if you are running Apache on the server you can put this in your .htaccess file which should allow you to directly go to any valid url. But seriously, I have worked for over a year with Angular now in a professional environment: nobody cares about the # in the url. It is easier to leave it there than trying to remove it.
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !index
RewriteCond %{REQUEST_URI} !.*\.(css¦js|html|png) #Add extra extensions needed.
RewriteRule (.*) index.html [L]
</ifModule>

Laravel 4 as RESTful backend for AngularJS

I am trying to build a web application which should use Laravel as a RESTful backend API and AngularJS on client side.
I read all the other post on Stackoverflow about the issue, but no one is definitely answering my doubts, at least, I did not find a definitive source example.
For instance...
Should I develop two completely distinct applications, a backend one with Laravel and another, purely client, with AngularJS?
But in this case: how to handle them through a single domain (or virtual host)?
Or should I create AngularJS templates inside Laravel, in the "views" folder and from them call Laravel services? I doubt this is the best approach: in this case the backend is not completely decoupled from the frontend implementation.
Also, how to correctly handle routing? I mean: I would like to manage from AngularJS routes like menu/page navigation, calling Laravel only to retrieve data and fill my views.
Moving the "public" folder as suggested in this post (Angular JS + Laravel 4: How to compile for production mode?) may help?
Thanx in advance for suggestions, examples...
Finally I found a working solution, perfect in my scenario, which does not require a subdomain.
In this case Laravel acts exclusively as a RESTful web service, no server side views or templates: the presentation layer is completely demanded to AngularJS.
Let's say I have two completely decoupled applications (FE e WS) inside the same root folder:
root
|__fe
|__ws
I modified virtual host settings under Apache httpd-vhosts.conf file the following way:
<VirtualHost *:80>
ServerName myapp.com
DocumentRoot "\www\root\fe"
alias /ws "\www\root\ws\public"
<Directory "\www\root\ws\public">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
I then added "RewriteBase /ws" into my laravel/public/.htacces file:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase /ws
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [NC,L]
</IfModule>
This way I can write in the browser (for instance):
http://myapp.com (AngularJS client side root)
http://myapp.com/ws/users (RESTful service endpoint for "users")
And then define a client side, AngularJS routing the following way:
app.config(function($routeProvider) {
$routeProvider
.when('/', {controller: 'HomeController', templateUrl: 'templates/home.html'})
.when('/users', {controller: 'UsersController', templateUrl: 'templates/users.html'})
.otherwise({redirectTo: '/'});
});
Linking it to a RESTful resource this way:
app.factory('User', function($resource) {
return $resource('http://myapp.com/ws/users');
});
app.controller('UsersController', function($scope, User) {
$scope.title = "Users";
$scope.users = User.query();
});
I enabled HTML5 history API, adding this line to configure my Angular application:
$locationProvider.html5Mode(true);
together with (inside index.html head section):
<base href="/" />
<meta name="fragment" content="!" />
So the last requirement to solve problems like browser page refresh, deep linking, or direct page bookmark, is to add a .htaccess file in the root of the folder which contains the Angular application:
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [NC,L]
</IfModule>
Hope it helps!
This is a half comment half answer, it got too long.
Matteo as you pointed out there are basically three different places you can do some sort of routing/redirecting with this stack. Ordinarily I haven't seen an advantage to doing the redirects at the Apache level, I imagine this might be more useful for localization or perhaps some sort of load/disk balancing. However you will have your VirtualHost configuration if you have multiple domains pointing to this address and you need to route those initial requests to the appropriate index.html (so if you consider this routing this would be my server side routing).
Generally speaking after that I rely on the Angular $routeProvider to handle client side "routes" really just mapping a URL to a view (possibly passing along some data).
I haven't gotten fancy with setting up a router in my PHP code to create a proper RESTful interface. In my particular case the data is being stored in a fairly abstract way and I had to do a fair amount of work in the PHP to get it organized in a coherent way, any straight ORM type solution wasn't going to work. This attempt has led me to consider options like MongoDB though since it should alleviate the workload necessary for doing the translation from persistent storage to client side and back.
Anyhow all that said I use $http to just make my calls from custom services to particular PHP endpoints that I need. My PHP folder with my scripts sits right next to where my index file is served up so requests from angular are all relative paths from the server root which keeps it simple. So they are physically "nested" so to speak or living side by side but the PHP code never writes any templates or affects the presentation it just gets data and serves it up (as JSON), so conceptually they remain separate.

CodeIgniter - Project is main website

This may be a potentially really, really dumb question.
So my CI project is going to be our main company website. I have created it here:
www.example.com/CodeIgniter_2.1.3
How do I get my users redirected to that when they just visit www.example.com/ and have it stay www.example.com in the URL?
Is this a .htaccess file thing? Or do I need to move my folders up a level?
CodeIgniter's default behavior is to hide it's actual path. You should only need to copy the .htaccess to the document root, and modify the path to include CodeIgniter_2.1.3
i.e:
RewriteRule ^(.*)$ /CodeIgniter_2.1.3/index.php?/$1 [L,QSA]
So you have put the CI files in a directory called Codeigniter?

Resources