grails 3.0.x url mapping dose not work - grails-3.0

where should i put class UrlMappings? under grails-app/conf/ or grails-app/controllers ??
the UrlMappings is below
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/checkpreload.htm"(view: "checkpreload")
"500"(view:'/error')
"404"(view:'/notFound')
}
}
checkpreload.gsp is under views folder, there is no controller associated with it, and it works in grails 2.4.4, but if i put the UrlMappings under controllers folder, return 404, if i put it under grails-app/conf, the return will be
javax.servlet.ServletException: Could not resolve view with name 'checkpreload' in servlet with name 'grailsDispatcherServlet'
plz help, i want to access a gsp file without controller associated

Related

Error download file PDF in Yii2: Unknown Method

I want to download file PDF from frontend/web/uploads. And I have an error in the controller (maybe):
Calling unknown method: frontend\controllers\BukuController::findModel()
This is my source code:
BukuController.php
public function actionDownload($id)
{
$model = $this->findModel($id);
$file ='../frontend/uploads/'.$model->file_buku;
if(file_exists($file))
{
return Yii::$app->response->sendFile($file);
exit;
}
}
And this is function in views, views/buku/index.php:
<?= Html::a('Download', ['download','id'=> $buku->file_buku]); ?>
(Solved)
As the error state, you missing in your BukuController method called findModel.
This method should search the model in the DB.
Something like this:
protected function findModel($id)
{
if (!is_null($model = Buku::findOne($id))) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
Of course if your model is not Buku, you need to change it relatively, and also import it in the top of the controller file:
use app\models\Buku; // Basic application.
use common\models\Buku; // Advanced application when models store in common folder.
use frontend\models\Buku; // Advanced application when models store in frontend folder.
Change $file variable to this.
$file =Yii::$app->getBasePath().'/web/uploads/'.$model->file_buku;

calling plugin's controller from AppController in CakePHP 3

I have written a plugin for CakePHP 3.4.*.
This plugin will check for Database configuration has been set or not, if not then It you move user through a GUI interface to setup database configuration just like wordpress.
The plugin is working perfectly, but it has to be loaded manually by visiting url of the plugin
http://example.com/installer/install
where installer is the plugin name which is calling InstallController class inside plugins/Installer/src/Controller/ directory
Now what I want to check it automatically and redirect user to the Installation interface if database connection couldn't be established.
For that I have written a function inside InstallController of plugin's controller
public function installationCheck() {
$db = ConnectionManager::get('default');
if(!$db->connect()) {
if(Configure::read('Database.installed') == true) {
$this->Flash->error(__("Database connection couldn't be established. Please, re-configure it to start the application"));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__("Please configure your database settings for working of your application"));
return $this->redirect(['action' => 'index']);
}
}
return true;
}
Now the Question.
What is the easiest way to call this method from /app/src/Controller/AppController.php file of the main application?
Simple answer, you don't!
Shared controller logic belongs either in AppController itself, a Component or a Trait. The AppController should never being accessing methods defined in other controllers, these shouldn't be made accessible to it.
For what you're doing you probably want to do this in a component that you can load via your AppController or the relevant controller.
So your component would look something like:-
<?php
namespace Installer\Controller\Component;
use Cake\Controller\Component;
class InstallComponent extends Component
{
public function installationCheck()
{
// Method's logic
}
}
Which you would then load in the relevant controller:-
public function initialize()
{
parent::initialize();
$this->loadComponent('Installer.Install');
}
Then you can use the component's method from the controller like:-
$this->Install->installationCheck();
You should not Do that!
If you need to access another controller I recommend you to move that functionality to a Component, that are packages of logic that are shared between controllers.

ASP.NET MVC bundle won't update if loaded dynamically

I have an Angular.js application, and, because it is a single page application, I'm loading some scripts dynamically, depending on the user navigation, so I don't get an overload.
The problem is, some of these scripts are uglified and minified in a ASP.NET MVC Bundle, and when I update a source script, the imported bundle never gets updated.
Why that happens, and what can I do to force an update?
Why that happens
The ASP.NET bundle comes with a caching mechanism. When you add the bundle to the page using Scripts.Render, the engine automatically puts a v query string into the bundle URL.
#Scripts.Render("~/bundles/commands")
produces something like:
<script src="/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"></script>
If this parameter is not provided, the cached result will be returned. If you add the script tag manually, without it, you can face the same caching issue.
Info about the v query string is provided here ("Bundle Caching"), but is not very helpful.
What can I do
You can still load the bundled scripts dynamically, but you will have to add the v parameter. Note that it doesn't work if you try a randomly generated hash (I tried). Thanks to Frison B Alexander, this is possible using this approach:
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
So what you can do is: Return the bundle hash from the ASP.NET view and get it when you need to load the script.
I my application, I created a JS object specific to it:
var appBundles = {
commands: "/bundles/commands?v=eiR2xO-xX5H5Jbn3dKjSxW7hNCH9DfgZHqGApCP3ARM1"
};
Hope this helps!
I had this problem with bundles not updating when I was loading bundles from one MVC app in another MVC app using GTM (sound messed up, but it actually makes sense in the context of multiple MVC apps sharing code between).
What I came up with is what Marcos Lima wrote in his answer, but taken a step further.
I've added a Bundle controller with following code:
public class BundleController : Controller
{
private static string GetHashByBundlePath(string bundlePath)
{
BundleContext bundleContext = new BundleContext(new HttpContextWrapper(System.Web.HttpContext.Current), BundleTable.Bundles, bundlePath);
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
BundleResponse bundleResponse = bundle.GenerateBundleResponse(bundleContext);
Type bundleReflection = bundleResponse.GetType();
MethodInfo method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
object contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
public ActionResult Index(string bundleName)
{
string bundlePath = "~/bundles/" + bundleName;
var hash = GetHashByBundlePath(bundlePath);
return RedirectPermanent(bundlePath + "?v=" + hash);
}
}
Then I've added this route:
routes.MapRoute(
name: "Bundle",
url: "Bundle/{bundleName}",
defaults: new { controller = "Bundle", action = "Index" }
);
The end result is that I request the bundles through the controller, but because I do a 301 redirect the Index action is run only once per user and it returns the current version of the bundle and the bundle is then served from browser cache afterwards. When I actually update the bundle I add some query parameter in the request url (in GTM) and all users now get the updated bundle.
Of course, I assume that bundles are placed in ~/bundles/ path, but that should be easy enough to change if yours are placed elsewhere. In fact the route isn't even necessary.

CakePHP change view for action in plugin

I'm developing a plugin that has an action which decide the view to render according to data properties:
example:
class ProfilesController extends MyPluginAppController {
public function myaction($id){
//..omitting checks..
$profile = $this->Profile->read(null,$id);
//Stuff
if($this->hasDedicatedViewFor($profile)){
$this->render('profiles'.DS.$this->getDedicatedViewFor($profile));
}
//Else render default action view
}
}
While this controller was inside the APP everything was working right,
after moving into Plugin, cake says:
Error: Confirm you have created the file:
.../app/View/Plugin/MyPlugin/Profiles/myaction_secondary.ctp
While I'd expect to load it from:
.../plugins/MyPlugin/View/Profiles/myaction_secondary.ctp
While I'd expect to load it from:
.../plugins/MyPlugin/View/Profiles/myaction_secondary.ctp
It is attempting to load the default plugin path
If you trace through the code for finding template files it is checking multiple paths for plugin view files:
$paths = $this->_paths($plugin);
$exts = $this->_getExtensions();
foreach ($exts as $ext) {
foreach ($paths as $path) {
if (file_exists($path . $name . $ext)) {
return $path . $name . $ext;
}
}
}
The path in the error message is the last place CakePHP looks for a plugin view path, but it should also be checking the plugins directory. Debug the above code to see where CakePHP is looking for files if in doubt.
The path being wrong in the error message probably indicates using an out of date version of CakePHP; it's always, always a good idea to maintain your applications running the most recent maintenance release for the major version you are using. From the info provided that's 2.7.3 at the time of this answer.

Nancy return view as either a rendered view or unrendered file

I'm trying to do something slightly unusual in allowing for a file to be returned by Nancy as both a rendered view and as an unrendered file if requested. My code is similar to:
public class MyModule : NancyModule
{
public MyModule() : base("/apath")
{
Get["/{Name}"] = parameters =>
{
return View[parameters.Name];
};
Get["/{Name}/AsFile"] = parameters =>
{
return Response.AsFile(parameters.Name);
};
}
}
My files are stored relative to the application root in /Views/apath
Nancy works perfectly when returning the file as a View, but returns a NotFound http status code when trying to serve it as a file.
I've been trying to change the path passed to Response.AsFile, but no luck as yet.
How can I get the AsFile route working?
Nancy does not support this out of the box, with good reason.
The thing that is super scary about what you're trying to achieve is, if I passed in a url like:
..%2Fweb.config
I could return the config file back, get access to your connection strings, and basically hack your website.
What you want to do is have some sort of look up table in a database, or a flat file or something that allows you to correlate a name to a physical file.
Name Path
my-cat ../pictures/cat/my-cat.jpg
my-dog ../pictures/cat/my-dog.jpg
Then you can look up the name, return the filename, and then use that in your existing code:
Get["/{Name}/AsFile"] = parameters =>
{
var file = myFileService.GetFile(parameters.Name);
return Response.AsFile(file.Path);
};
Also if the file doesn't exist, then you know it might be an unsafe request and can tell the user to get lost!

Resources