How do I create and use a Form helper in a plugin? - cakephp-3.7

I'm trying to extend the FormHelper to include some custom controls. I want to do this as part of a plugin. The documentation is a bit sketchy on how to achieve this.
I've created the desired helper in the following folder structure:
\plugins\MyPlugin\src\View\Helper\MyFormHelper
The helper looks like this:
<?php
use Cake\View\Helper\FormHelper as BaseFormHelper;
class MyFormHelper extends BaseFormHelper
{
}
... yes it's empty for now. The docs on plugins is a bit vague but it seems to say that one can load this helper in the following way within the main application's AppView.php::initialise() method:
$this->loadHelper('MyPlugin.MyFormHelper');
However this doesn't work. Doing it this way I get a FATAL error:
Fatal error: Cannot declare class MyFormHelper, because the name is already in use in /Users/geoidesic/MyApp/plugins/MyPlugin/src/View/Helper/MyFormHelper.php on line 12
The question is then how to make use of this plugin helper? Specifically I'd like to override the default FormHelper for the app. There is a className option for loadHelper but I can't find a way to make that work with the plugin helper either.

I was missing the namespace for the helper. Should be like this:
<?php
namespace MyPlugin\View\Helper
use Cake\View\Helper\FormHelper as BaseFormHelper;
class MyFormHelper extends BaseFormHelper
{
}

Related

Creating a component from a plugin's element when plugin is already inside another component

I'm using a third-party plugin and I have no control over it. I'm using Ember in my entire application except for this plugin and I need instantiate a component inside a div rendered by said plugin to control it the way I want (to avoid the use of jQuery events and such).
1- I'm creating a component called "MyNewComponent"
2- The current structure:
<myComponent1>
<myPlugin-notEmber>
<div-where-I-want-to-append-MyNewComponent class="divClass"/>
</myPlugin-notEmber>
</myComponent1>
3- Take into account that the "div-where-I-want-to-append-MyNewComponent" is rendered by the plugin, not by me.
4- What I'm currently trying to do inside myComponent1 is:
onDidInsertElement: Em.on('didInsertElement', function() {
this.$().find('.divClass').each(function(index, element) {
MyNewComponent.create().appendTo(Em.$(element));
});
}),
Why it's not working:
I'm getting this: (Ember 1.13)
"You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead."
What I'm looking for:
a) the right way to do this OR
b) an equivalent alternative (that will create a component inside that plugin)
Your best option would be to use ember-wormhole
Which allows you to place anything inside another div with an id, so:
{{#ember-wormhole to="destination"}}
{{my-new-component}}
{{/ember-wormhole}}
And somewhere else you'd have
<div id="destination"></div>
This will render the {{my-new-component}} inside of that div.

Ember-cli addons and helpers

What is the correct way of placing your helper files and also where should they go with respect to the resolver finding them from an addon ember-cli project?
I am running ember-cli 0.2.2.
I generated an helper from an addon project with:
ember g helper display-helper
The generator placed the file in app/helpers which seemed wrong to me, I would have thought that it should have been placed in addon helpers. I moved the file to addon/helpers and it looks like this:
export default Ember.Handlebars.registerBoundHelper('displayHelper', function displayHelper(searchPath) {
return new Ember.Handlebars.SafeString(get(this, searchPath));
});
When I ran ember test I get the following output:
✘ Error: Assertion Failed: A helper named 'displayHelper' could not be
found
The only way I get this helper to be found by the resolver is to add an import that references the helper in a component that is using it like this:
import displayHelper from '../helpers/display-helper';
This does not seem correct, I would have thought the resolver would have found this automatically?
Also even if I have the reference, the following code ends up with the same error message as above:
import Ember from 'ember';
var get = Ember.get;
function displayHelper(context, searchPath) {
return new Ember.Handlebars.SafeString(get(context, searchPath));
}
export default Ember.Handlebars.makeBoundHelper(displayHelper);
So to sum up, I have to have this line in the component whose template uses the helper:
import displayHelper from '../helpers/display-helper';
And I have to use registerBoundHelper and not makeBoundHelper like the docs say or the helper cannot be found.
If you move your helper from app/helpers to addon/helpers, it is not available in your app namespace. To fix this, add the following file:
// app/helpers/display-helper.js
import displayHelper from 'your-addon-name/helpers/display-helper";
export default displayHelper;
(Do not copy your-addon-name literally, use the name of your addon, which is also your addon's namespace.)
This is based on the instructions here:
http://www.ember-cli.com/#addon-components
Just like the example component there, you can put your real helper code in addons/helpers/display-helper, but you need to import and reexport it to your app for your resolver to find it.

Using Ember CLI Addon Models in Ember Application?

I want to allow something like the following to work in my application:
store.find('my-addon.my-addon-model', 1)
store.find('my-addon/my-addon-model', 1)
store.find('my-addon:my-addon-model', 1) (unlikely)
The thing is I want it to search for a model that is 100% defined in an addon.
import MyAddonModel from 'my-addon/models/my-addon-model' works from within my app - but container resolution doesn't...
How would I do/allow this?
This question is the same as:
Registering models from another namespace with the Ember Data store
However the naming there is a bit confusing. When trying this out I also seem to have hit a bug in ember-data#1.0.0-beta.15.
What you need to do in your module initializer is register the model(s) to your application.
import Ember from 'ember';
import MyModel from my-module/models/my-model';
export default {
name: 'my-module-models',
initialize: function(container, application) {
//one of these calls for each model you need to register
application.register('model:myModule.myModel',MyModel);
}
};
Now according to my experience with Ember and Ember-Data, this is supposed to work just like that. But in my setup with ember-data#1.0.0-beta.15 there seems to be an issue determining the models "key" after creation. The model instance is created fine, but you will hit an error trying to save the model.
I've found a quick workaround, but it's a hack and I would need to investigate further whether I'm missing a step or it's a bug. The workaround involves setting the "typeKey" of the class, resulting in:
import MyModel from my-module/models/my-model';
export default {
name: 'my-module-models',
initialize: function(container, application) {
//one of these calls for each model you need to register
application.register('model:myModule.myModel',MyModelreopenClass({typeKey:'myModule.myModel'}));
}
};
Finally, there is another way around. When creating modules in ember-cli, you have the app folder which will be merged with the app using your module. You could place default extends of your model(s) in the app folder.

Emberjs: Access controller dependency on a different namespace

In my ember application I want to have modules on different namespaces. I have an App Namespace and for each module there is an App.ModuleName namespace.
So far so good, I can access everything so far using App/ModuleName/SomeResource syntax. Now I have a controller that has a dependency on a controller in one of the module namespaces. I put up the controllers like this:
App.ModuleName.FooController = Ember.Controller.extend({
fooVal: 42
});
App.SomeController = Ember.Controller.extend({
needs: ['App/ModuleName/Foo', 'bar']
});
That seem to work so far telling by ember not complaining that the needed controller doesn't exist.
Now, how do I acces the controller in my handlebars template? For the bar controller its easy, just using controllers.bar.someProperty but I cannot access the App.ModuleName.FooController. I tried:
{{controllers.App/ModuleName/Foo.fooVal}}
{{controllers.App.ModuleName.Foo.fooVal}}
{{controllers.Foo.fooVal}}
and so on, every combination I could think of but it didn't work. Is it possible (and how) to get this running? Can someone please enlighten me?
And by the way: Even on the controllers I use needs successfully, if I debug them (logging them into the console, from my code directly or with a handlebars helper) the controllers property is always undefined. Is there a way to check the needed controller references?
Many thanks in advance.
To my knowledge, Ember's Container looks up stuff via the resolver. And it only looks for stuff on the application's namespace.
Some examples from the DefaultResolver docs.
'controller:post' //=> App.PostController
'controller:posts.index' //=> App.PostsIndexController
'controller:blog/post' //=> Blog.PostController
'controller:basic' //=> Ember.Controller
To achieve what you need you will need to provide a custom Resolver that looks up stuff in the different namespace when creating the Application.
App = Ember.Application.create({
resolver: MyNewResolver
});
For everyone who is interested in how I solved the issue and what I tried and learned:
I did some diggin in the code and tried a few things. I got the desired output using
a) A custom Handlebars helper that returns the property of the controller like this:
{{ myhelper 'App.ModuleName.FooController' 'fooVal'}}
with the following (quick and dirty) helper:
Ember.Handlebars.registerBoundHelper('myhelper', function(arg1, arg2, opts) {
if (opts && opts['data']) {
var ctrl = opts.data.properties[0];
var prop = opts.data.properties[1];
var controller = this.get('container').lookup('controller:' + ctrl.split('.').join('/'));
if (controller) {
return controller.get(prop);
}
}
});
The problem with this is, I couldn't get databinding to work, so if I changed my underlying model, the view didn't update.
b) Overriding the Controllers init() method to get the controller instance like this:
init: function() {
this.module = this.get('container').lookup('controller:App/Module/Foo');
}
and then in the template:
{{module.fooVal}}
In the second way, also Databinding worked, but It didn`t feel correct, so I did some googlin and came across this post on the emberjs issue list:
https://github.com/emberjs/ember.js/issues/683#issuecomment-5122333
As stated by tomdale, nested namespaces are not really something that is encouraged in ember, but multiple 'toplevel' namespaces are ok. So I decided to put up a toplevel namespace for every module and use a custom resolver to resolve them. Works like a charm now and feels like the right way to do it.
Any additional suggestions and comments about the pro's and con's of my second and final way of solving the problem would be much appreciated.

How can I create a class method using AppleScriptObjC

I'm trying to override the +initialize method of a class using ASOC, but I cannot find a way to override a class method. Is it even possible?
Not to let any confusion possible about the language I'm talking about, here's some code:
script FLAppDelegate
property parent: class "NSObject"
-- -- Class Methods -- --
-- Insert code here
end script
I've done some tests, and as far as I can tell, weird as it is, methods defined using AppleScriptObjC are both class and instance methods.
Let's say I have an AppleScriptObjC file:
script iTunesController
property parent: class "NSObject"
on playpause()
tell application id "com.apple.iTunes" to playpause
end playpause
end script
In an Objective-C method, both:
- (void)callASOC
{
iTunesControllerInstance = [NSClassFromString(#"iTunesController") new];
[iTunesControllerInstance playpause];
[iTunesControllerInstance release];
}
and
- (void)callASOC
{
[NSClassFromString(#"iTunesController") playpause];
}
will call the playpause handler in the AppleScriptObjC file. The latter formulation will generate a warning a compile time, but works.
I was not able to find any documentation confirming or refuting this.
Thanks to #Friziab who reminded me of the NSClassFromString
So I could call a AppleScriptObjC method in my AppDelegate.applescript from another class (script) (NSView subclass)
I don't use AppleScriptObjC so there may be a proper way of doing it but this worked
current application's NSClassFromString("AppDelegate")'s popWindow()