I'm working in a Zend Framework based application (Shopware).
I add a template dir in my controller like this:
class Shopware_Controllers_Backend_Pricify extends Shopware_Controllers_Backend_ExtJs
{
public function init()
{
$this->View()->addTemplateDir(dirname(__FILE__) . "/../../Views/backend/");
parent::init();
}
}
But somehow, smarty always looks in the (not existing) part of the controller action:
Unable to load template snippet 'backend/mycontroller/model/main.js' in 'snippet:string:{include file="backend/pricify/model/main.js"} in Smarty/sysplugins/smarty_internal_templatebase.php on line 128
The Controller works over loading via ext js, but I do not see that this is a problem. When I var_dump template directories, the correct dir is included. I debugged the code far into smarty, but never found the part, where the directories are checked.
I'm aware, that this may be a problem within the software stack, but since I do not know where to search, I ask here. If I need to post additional data, please tell me.
I found, that the problem was that shopware extends CamelCase to camel_case folders.
Related
How to exclude UnityEditor reference from asmdef?
Why I need it:
I have an asmdef file. For example, it is MyAssembly/MyAssembly.asmdef. The MyAssembly contains a lot of features and each feature staff is placed in its own folder. And some of these features has a code that is needed only in editor, and it refers to UnityEditor namespace. Such editor code is placed into an Editor folder.
But as you know, Editor folder name means nothing in terms of asmdef usage. So I add AssemblyDefenitionReference in each folder and refer it to the MyAssemblyEditor.asmdef assembly definition. So the paths looks like this:
MyAssembly/MyAssembly.asmdef
MyAssembly/Editor/MyAssemblyEditor.asmdef - this folder contains no code. It's needed just to place asmdef, because it's not allowed to place two asmdefs in a single folder.
MyAssembly/SomeFeature/Editor/*feature editor staff*
MyAssembly/SomeFeature/Editor/Editor.asmref - refers to MyAssemblyEditor.asmdef
MyAssembly/SomeFeature/*feature staff*
All this works good. But the problem is that, when some developer adds a new feature, he can forget to add a reference to the MyAssemblyEditor.asmdef in the editor folder. And there are no any errors will be shown in this case. This mistake will be revealed only when the build will be cooked. But I'd like that using of UnityEditor in MyAssembly will be instantly marked as an error.
Feel free to suggest other solution for this problem.
This thread got me thinking I can use CsprojPostprocessor to remove all references to UnityEditor from my csproj file. I wrote such class:
using System.Text.RegularExpressions;
using UnityEditor;
// ReSharper disable once CheckNamespace
public class CsprojPostprocessor : AssetPostprocessor
{
public static string OnGeneratedCSProject(string path, string content)
{
if (!path.EndsWith("Editor.csproj") && !path.EndsWith("Tests.csproj"))
{
var newContent =
Regex.Replace(content, "<Reference Include=\"UnityEditor(.|\n)*?</Reference>", "");
return newContent;
}
return content;
}
}
It also can be done with an xml parser or something.
The only thing, that confuse me is that this mechanism is badly documented and doesn't look like something simple users should use. So I use it at my own risk, but looks like there is no guarantee it will be strongly supported in future.
I need to include a PHP script in my TS template :
page {
10 = USER_INT
10.includeLibs = lib_confidential.php
10.userFunc = MyClass->ConfidentialRequest
}
It works perfectly but I would like to locate the lib_confidential.php outside of my website root directory (and make something like 10.includeLibs = ../lib_confidential.php). Is it possible to secure my PHP script and how to ? I thought about creating a symlink but that doesn't give any solution.
As your installation needs an update you will have to change the mechanism for including php-functions for the future.
since TYPO3 8 you need to have a class for your php functions. So the autoloader can identify the class and execute the function you need to place the class inside of an extension or declare the class to the autoloader.
Best practice would be site extension where you configure your installation, there you can havea class with all the functions you need.
examples can be found in the manual.
Given you are in a BE or CLI context (e.g. sending emails via extbase command controller task), the following worked up to 7 LTS for rendering a fluid standalone view:
$view = $this->objectManager->get(StandaloneView::class);
$view->setTemplatePathAndFilename('/Absolute/Path/To/Template.html');
$view->setFormat('html');
$view->getRequest()->setControllerExtensionName('Myextensionname');
return trim($view->render());
However, in 8 LTS, this throws the following exception:
Tried resolving a template file for controller action "Standard->index" in format ".html", but none of the paths contained the expected template fileā¦ No paths configured.
As suggested in the wiki page at https://wiki.typo3.org/How_to_use_the_Fluid_Standalone_view_to_render_template_based_emails#Usage_in_TYPO3_8.7, I tried setting layout and partial root paths for the view:
$view->setLayoutRootPaths(['EXT:Myextensionname/Resources/Private/Layouts/']);
$view->setPartialRootPaths(['EXT:Myextensionname/Resources/Private/Partials/']);
However, this won't do the trick.
Digging a bit deeper, I could imagine that one would have to set the controller and action name, e.g. by setting the controller context, but that does not seem to be a solid solution as multiple other class instances are tied to it.
What is the correct way to render fluid standalone views in 8 LTS?
Here an example from our current webproject where we want to show a simple note in backend context based on a FLUID HTML in TYPO3 8.7
protected function renderMarkup(): string
{
$standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
$standaloneView->getRequest()->setControllerExtensionName('in2template');
$templatePathAndFile = 'EXT:in2template/Resources/Private/Templates/Tca/ToolbarNoteEmptyFields.html';
$standaloneView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFile));
$standaloneView->assign('toolbar', 'toolbarstuff');
return $standaloneView->render();
}
StandaloneView likes to receive all template paths (partial, template and layout root paths) so if you don't already provide all of them, you should do so. The reason being that the naming "Standalone" refers to the view being tied neither to a specific MVC action nor a specific extension context.
That said, if you use 8.7.5 there's a chance you are hit by a regression that is going to be solved by https://review.typo3.org/#/c/53917/ so it might be worth checking that out before you do a major refactoring. Technically the StandaloneView can be operated like a TemplateView with extension context, it's just not officially supported behavior and TYPO3 may not consistently apply all of the context you expect.
In my 8.7 extension I use the following code to get the StandaloneView:
$extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
/** #var StandaloneView $emailView */
$emailView = $this->objectManager->get(StandaloneView::class);
$emailView->getRequest()->setControllerExtensionName($controllerExtensionName);
$emailView->getRequest()->setPluginName($pluginName);
$emailView->getRequest()->setControllerName($controllerName);
$emailView->setTemplateRootPaths($extbaseFrameworkConfiguration['view']['templateRootPaths']);
$emailView->setLayoutRootPaths($extbaseFrameworkConfiguration['view']['layoutRootPaths']);
$emailView->setPartialRootPaths($extbaseFrameworkConfiguration['view']['partialRootPaths']);
$emailView->setTemplate('Email/' . ucfirst($templateName));
$emailView->assignMultiple($variables);
$emailBody = $emailView->render();
In my function I gave the $controllerExtensionName, $pluginName and $controllerName as parameter with default values, so that other controllers/plugins can use this function, too.
I'm looking specifically for a way to automatically hyphenate CamelCase actions and views. That is, I'm hoping I don't have to actually rename my views or add decorators to every ActionResult in the site.
So far, I've been using routes.MapRouteLowercase, as shown here. That works pretty well for the lowercase aspect of URL structure, but not hyphens. So I recently started playing with Canonicalize (install via NuGet), but it also doesn't have anything for hyphens yet.
I was trying...
routes.Canonicalize().NoWww().Pattern("([a-z0-9])([A-Z])", "$1-$2").Lowercase().NoTrailingSlash();
My regular expression definitely works the way I want it to as far as restructuring the URL properly, but those URLs aren't identified, of course. The file is still ChangePassword.cshtml, for example, so /account/change-password isn't going to point to that.
BTW, I'm still a bit rusty with .NET MVC. I haven't used it for a couple years and not since v2.0.
This might be a tad bit messy, but if you created a custom HttpHandler and RouteHandler then that should prevent you from having to rename all of your views and actions. Your handler could strip the hyphen from the requested action, which would change "change-password" to changepassword, rendering the ChangePassword action.
The code is shortened for brevity, but the important bits are there.
public void ProcessRequest(HttpContext context)
{
string controllerId = this.requestContext.RouteData.GetRequiredString("controller");
string view = this.requestContext.RouteData.GetRequiredString("action");
view = view.Replace("-", "");
this.requestContext.RouteData.Values["action"] = view;
IController controller = null;
IControllerFactory factory = null;
try
{
factory = ControllerBuilder.Current.GetControllerFactory();
controller = factory.CreateController(this.requestContext, controllerId);
if (controller != null)
{
controller.Execute(this.requestContext);
}
}
finally
{
factory.ReleaseController(controller);
}
}
I don't know if I implemented it the best way or not, that's just more or less taken from the first sample I came across. I tested the code myself so this does render the correct action/view and should do the trick.
I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.
Uppercase urls are problematic because cookie paths are case-sensitive, most of the internet is actually case-sensitive while Microsoft technologies treats urls as case-insensitive. (More on my blog post)
NuGet Package: https://www.nuget.org/packages/LowercaseDashedRoute/
To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.
Alternatively, you can run this code in the Package Manager Console:
Install-Package LowercaseDashedRoute
After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:
routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
new DashedRouteHandler()
)
);
That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.
Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route
Have you tried working with the URL Rewrite package? I think it pretty much what you are looking for.
http://www.iis.net/download/urlrewrite
Hanselman has a great example herE:
http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx
Also, why don't you download something like ReSharper or CodeRush, and use it to refactor the Action and Route names? It's REALLY easy, and very safe.
It would time well spent, and much less time overall to fix your routing/action naming conventions with an hour of refactoring than all the hours you've already spent trying to alter the routing conventions to your needs.
Just a thought.
I tried the solution in the accepted answer above: Using the Canonicalize Pattern url strategy, and then also adding a custom IRouteHandler which then returns a custom IHttpHandler. It mostly worked. Here's one caveat I found:
With the typical {controller}/{action}/{id} default route, a controller named CatalogController, and an action method inside it as follows:
ActionResult QuickSelect(string id){ /*do some things, access the 'id' parameter*/ }
I noticed that requests to "/catalog/quick-select/1234" worked perfectly, but requests to /catalog/quick-select?id=1234 were 500'ing because once the action method was called as a result of controller.Execute(), the id parameter was null inside of the action method.
I do not know exactly why this is, but the behavior was as if MVC was not looking at the query string for values during model binding. So something about the ProcessRequest implementation in the accepted answer was screwing up the normal model binding process, or at least the query string value provider.
This is a deal breaker, so I took a look at default MVC IHttpHandler (yay open source!): http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs
I will not pretend that I grok'ed it in its entirety, but clearly, it's doing ALOT more in its implementation of ProcessRequest than what is going on in the accepted answer.
So, if all we really need to do is strip dashes from our incoming route data so that MVC can find our controllers/actions, why do we need to implement a whole stinking IHttpHandler? We don't! Simply rip out the dashes in the GetHttpHandler method of DashedRouteHandler and pass the requestContext along to the out of the box MvcHandler so it can do its 252 lines of magic, and your route handler doesn't have to return a second rate IHttpHandler.
tl:dr; - Here's what I did:
public class DashedRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["action"] = requestContext.RouteData.GetRequiredString("action").Replace("-", "");
requestContext.RouteData.Values["controller"] = requestContext.RouteData.GetRequiredString("controller").Replace("-", "");
return new MvcHandler(requestContext);
}
}
I noticed that the blog module for SS have hardcoded pieces of text - that I need to translate (in french). I found that the code is in /blog/templates/Includes/BlogSummary.ss but when I modify it, nothing changes on front-end...
I tried to run a /dev/build/?flush=all but nothing... still.
Any idea? Help would be much appreciated. Thanks in advance.
Have you set your locale? I recently set up a site in English & Spanish and used this setup.
// add similar code to your _config.php file
#Translatable::set_default_locale('en_US');
#Translatable::set_allowed_locales(array(
# 'en_US',
# 'es_US'
#));
Further, I had to add i18n::set_locale() code to the init() function in my content controller to get the template translations to work.
<?php
class SmartLanguageExtension extends DataObjectDecorator {
function contentcontrollerInit() {
i18n::set_locale(Translatable::get_current_locale());
}
}
In my case, I added an extension to the Page_Controller class for reusability later on.
// _config.php file
Object::add_extension('Page', 'SmartLanguageExtension');