Foreseen way to access a component from another component in Yii2? - yii2

Would it be a bad practice to access an application component from another component? If yes: why? If no: What would be the best practice to do that? I didn't find any good advice for this question in the guide.

You can access any component from anywhere in you application via Yii::$app->componentName.
But i don't think that this is a good practice to do it directly that way.
At least, to keep your component isolated, you should keep in mind that componentName is a subject op parent application configuration.
So as minimum you should include the name of referenced component into dependent component configuration.
In your components/MyComponent.php:
class MyComponent extends Component
{
public $referencedComponentName = 'defaultName';
...
}
In config/web.php:
...
components => [
'myComponent' => [
...
'referencedComponentName' => 'otherComponent'
]
]
So you can call other comonent in your component code like this:
use yii;
...
class MyComponent extends Component
{
...
public function getReferencedComponent()
{
return \Yii::$app->get($this->referencedComponentName);
}
But this way also not very good. According to SOLID Depenency inversion principle the better way will be to define some abstraction for
referenced component (interface for exampe), which will be implemented in parent application config. But here i cant't provide valuable example
because i don't know your particular task and application structure.

Related

Yii2: Attach behavior to every controller

How do we attach a behavior to all web controllers in the application?
I understand this is theoretically possible with dependency injection, so I assumed something like this would work:
Yii::$container->set('yii\web\Controller', [
'as myBehavior' => [
'class' => 'app\behaviors\MyBehavior',
],
]);
however DI requires an exact class match (attaching to a parent class will not work). There is no way to know all the controller names in advance, especially when most are coming from 3rd party modules.
Is there another way to accomplish this?
EDIT: The purpose of this is to dynamically add controller filters (which are just a special type of behaviors). Therefore attaching the behavior during the EVENT_BEFORE_ACTION event is not sufficient, because it is triggered long after request filtering.
The module's (and application's) beforeAction event is triggered before the controller's version of that event. You can take advantage of that and use it to attach behaviors to current controller.
For example in your web.php config:
return [
'on beforeAction' => function() {
Yii::$app->controller->attachBehavior(
'myBehavior',
\app\behaviors\MyBehavior::class
);
},
// ... other configurations
];
Of course the disadvantage is that the behavior is not attached from the start.
NOTE: If your goal is attaching a filter to each controller, you can simply attach it to application itself instead of controllers.
Interesting problem, I must say. I could not find the simple solution for this but I have this hacky idea. You could take advantage of Yii autoloader and load your version of yii\web\Controller instead of the original one.
To do that:
Copy the original file from vendor and place it in your app
Don't change the original namespace and name.
Add your behavior config (or just the behavior's code, whatever) inside.
Add this line below in a place that will be called every time the app runs (like entry point file or bootstrap file, it must be called after vendor/yiisoft/yii2/Yii.php file is required):
Yii::$classMap['yii\web\Controller'] = ''; // replace '' with the path to your version
// of yii\web\Controller
Now, every time autoloader tries to load yii\web\Controller it will load your version instead so it should work like you want it.
The obvious con of this is that you will have to check manually if the original file has not been updated when upgrading Yii to make it up-to-date.
Child controller behavior depends on AccesControler behavior
class WorkerimgController extends OfficeController{
public function behaviors()
{
return ArrayHelper::merge(parent::behaviors(), [
]);
}
}

how to avoid re-definition web component in lit-element?

import { LitElement, html } from 'lit-element';
class MyPublic extends LitElement {
render(){
return html`
<p>A paragraph</p>
`;
}
}
customElements.define('my-public', MyPublic);
I defined a public web component like that in MyPublic.js. And then when I need to use it in FooComponent.js, I will import MyPublic.js, when I need to use it in BarComponent.js, I will also import MyPublic.js. It will cause re-definition for my-public.
How to avoid it?
Just import all the web components in index.js, and then don't import it anymore?
No, this will not cause a re-definition of your element, the same way your final (live) JavaScript code in the browser doesn't contain a dozen copies of the LitElement or Polymer library.
Imports are de-duped by the browser's runtime. This implies that global variables defined in a module also exist only once in memory, and more generally that free code in modules is only executed once.
You can read more about this in the spec. But essentially:
This [import] operation must be idempotent if it completes normally. Each time it is called with a specific referencingScriptOrModule, specifier pair as arguments it must return the same Module Record instance.

Using same model from store in a component used in all routes in Ember 2.8.0

My use case: application has a header that displays current user's name. This header is the same on all pages.
User data is loaded from JSON API into the Store when user logs in.
Now, how am I supposed to access this data from Store to use it on every page?
One option is to pass it from routes:
{{app-header user=model}}
But then I would have to use the same model in all the routes and also would be unable to use any other? How can a (supposedly reusable) component expect from me to adjust every route to its data structure?
The other option is that component always loads data from Store on its own, but this seems strongly unrecommended and actually very hard to do for me without any proper guide. I managed to discover service injection method (store: Ember.inject.service() in the component) but still can't get the component to properly display data from store in the template.
When I use:
name: () => {
return this.store.peekRecord('user', 1).get('name');
}
then {{name}} in template renders function definition, not what it returns.
When I use:
name: Ember.computed(() => {
return this.store.peekRecord('user', 1).get('name');
})
then {{name}} renders: <!---->
Could you please explain what is a good way to do this? Is there some "master model" defined in application.js besides models from routes? Should I really pass the same data to component in every route? Any information or suggestions will be greatly appreciated.
You could try using a service (guide here).
// app/services/store.js
import DS from 'ember-data';
export default DS.Store.extend({});
// app/services/user-service.js
import Ember from 'ember';
export default Ember.Service.extend({
store: Ember.inject.service(),
user: Ember.computed(function() {
return this.get('store').findRecord('user', ':id');
})
});
Then, in all your other components, controllers, and routes, you can access the service.
// Inside a controller
export default Ember.controller.extend({
userService: Ember.inject.service(),
firstName: Ember.computed.alias('userService.user.firstName')
});
The first name, or even the user object itself is now available in you template.
{{userService.user.firstName}}
OR
{{firstName}}
First approach, (Keeping it in Application Route)
1.Define it in application route model hook - refer multiple modelsin single route.(https://guides.emberjs.com/v2.9.0/routing/specifying-a-routes-model/#toc_multiple-models)
2.If its required in another route, then you can access already resolved model of the parent route through modelFor method.(http://emberjs.com/api/classes/Ember.Route.html#method_modelFor)
Second Approach, (Service)
Like #devman answer, you can load it in service and inject and get it wherever you require.
userService:Ember.inject.service();
name: Ember.computed.alias('userService.name')

Return read-only ui component in Flex

In Flex, I want to create some variable that would hold a dictionary of ui components used throughout my application. Ideally, there would be a function in Application component that would return component for id:
public function getComponent4Id(id:String):UIComponent {}
Then I would access component using the following line:
var myComponent:UIComponent = FlexGlobals.topLevelApplication.getComponent4Id("someId");
Now, the only problem is: I want the component returned to be read-only.
It is very convenient to read some properties of myComponent from every corner of application, but I don't want my developers to abuse it and change myComponent.
Is it possible to return a copy of myComponent? Or is it possible to make it read-only somehow?
In the situation you describe, it is not possible to retrieve read only components.
You can create read only variables by implementing get methods without set methods. Something like this:
public var get myValue():UIComponent{
return UIComponent;
}
This would allow you to retrieve the UIComponent instance, myValue, from the component; but you would not be able to set it.
However, this would not prevent people from changing properties on the returned UIComponent unless those properties were also implemented as read only.
I'll add that there is already a method, getChildByName() to retrieve a child component by name. If you have an instance to a parent, you can use this to access the children.
All that said, I'm not sure I completely understand what you hope to achieve; with this functionality.

When should I use/examples of nested classes?

Please retag this question to include languages to which it is relevant
So my java book had a whole chapter on nested classes, but ended on the note that you should only really use them when it comes to "modeling composition relationships and implementing internals of a class you want to hide". So lets discuss when you would want to use nested classes and some examples.
A nested/inner class is just a class that's only ever used specifically in the context of another class, which doesn't have it's own class file. If it's linked to an instance, it can only be instantiated in the context of a parent class instance; it can see private data, or only private static data if it's a static class.
The java developer site has a nested classes tutorial with one example:
http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html
A couple examples of usage:
Hide a concrete implementation of an
interface:
(Thinking of a database session for a tool like Hibernate): Suppose you have a Session interface, and a SessionFactory which returns an instance of a Session. The SessionImpl concrete class that implements the Session interface could be an innner class of the factory that knows how to construct and initialize it.
Supply information by implementing an
interface:
In the Wicket web framework, each GUI component has an associated "model", whose job is to wire data to the component. The interface looks something like:
public interface IModel extends IDetachable {
public Object getObject();
public Object setObject();
}
Suppose you have some special logic to retrieve data for a custom GUI component that you've written. Since no other component retrieves data the same way, you could use an anonymous class at the point where the IModel is supplied to take care of the data retrieval. If you have another point in the same class where you need to reuse your IModel implementation, you could make it an inner class. Later, if you need the model elsewhere, you could convert it to a top-level class.
Generally you use an inner class in a situation where you need a class definition, but that class is only usable or only makes sense in the context of the parent class.
A real life usage i had with nested classes, was in a global settings object.
The parent class was a Singleton, with nested classes as settings categories.
Settings
File settings
Print settings
Etc.
There was no real point in making the inner object as separate classes, as their would be no use for them outside the settings class scope.
I use nested classes for encapsulating algorithms that would be usually done as a method with lots of arguments. I use class that has raw data and I put algorithms into separate file in nested class (using partial keyword). That way I can put properties for that algorithm and its (working) data lives after algorithm is done.
I know that can be easily done without nested classes but this feels right because algorithm is purposely built for parent class.
public partial class Network
{
partial void initFDLF()
{
fdlf=new FDLF(this);
}
public FDLF fdlf;
public class FDLF
{
internal bool changed=true;
internal bool pvchange=true;
public double epsilon = 0.001;
public bool fdlfOk=false;
public void init(){...}
public void run(){...}
...