Overloading standard getters - yii

I want to make a custom getter that should return two fields of the model instead of one. I have the attribute name like first_name. And the getter I am making is
public function getFirstName(){
return 1;
}
And then I try to get it called in a CDetailView like this
'client.first_name:raw:Client',
But it returns the standard attribute of the model. How to do it right?

Yii's order of operations to retrieve an attribute is as follows:
AR attribute
public variable
custom getter
I'm not sure whether AR attributes or public variables are pulled first, but I do know that if either of them exist, your custom getter won't be called.
If you already have a first_name attribute (from AR), then you'll need to use a different name for your getter and use that.

Related

Avoiding setter to change value of class's property

I have a class with one private field:
class Person {
string name;
public void setName(string name);
}
Then, using some object which is responsible for interacting with user (in this example by command line), I want to change the value of this field:
Person somePerson;
CommandLineView view;
somePerson.setName(view.askUserForName());
It works. But I don't like using set function as it exposes class members.
Therefore I started looking how to avoid it.
New implementation looks like this:
class Person
{
string name;
public void changeName(view) { name = view.askUserForName(); }
}
and:
Person somePerson;
CommandLineView view;
somePerson.changeName(view);
Now Person does not expose its member. Moreover this class is responsible for logic related to changing name (for example function changeName could also update database, notify interested parties etc.
The question is: Is such kind of refactoring a good practice? Or maybe implementation with setter was better, even if it break encapsulation?
I think there should be no method to set the name at all, it should be a constructor parameter:
Person somePerson(view.askUserForName());
Problem with your approach is that you first create the object which is not fully initialized, so is dangerous to use: Person somePerson. What if you forget to setName? Will your code still work with this "empty" person?
And then you allow to directly modify the internal state with setName method, which is also not good.
Using the constructor parameter you avoid both of these problems.
As for the original question - I don't think there is big difference between the two methods.
The result is exactly the same - you call the method and the internal object state changed. You can name it setName or changeName, result is the same.
The second method with changeName(view) actually is worse because you also introduce the dependency of the Person on the View object.
Now, if you want to change the name, you always need to create the View object first.

How to get the translation of an enumeration field?

In an entity, I have an enumeration field which is translated in english and french.
In the same entity, I have a computed field that I am using as a toString, so I would like to build the computed field with the enumeration value translated in english or french, depending on the user's locale.
My question : in the getter of my computed field written in the extension of the entity, how could I get the user's locale and translate the enumeration value ?
You have to make your extension aware of its execution context. There are several interfaces that you can implement in your extensions so that they get injected with elements of their running context.
org.jspresso.framework.model.component.IComponentFactoryAware to receive an ICompoentFactory instance
org.jspresso.framework.security.ISubjectAware to receive the instance of the logged-in Subject
org.jspresso.framework.application.backend.session.IApplicationSessionAware to receive the current instance of IApplicationSession
org.jspresso.framework.model.entity.IEntityLifecycleHandlerAware to receive an instance of IEntityLifecycleHandler
In order to fulfill your use-case, the 4th interface must be implemented. Your extension will be injected with an instance of IEntityLifecycleHandler through the following method :
void setEntityLifecycleHandler(IEntityLifecycleHandler);
Just store this instance in your extension implementation as an instance parameter and use it afterwards in your code by safely casting it as a org.jspresso.framework.application.IController.
For instance :
public String getI18nLabel() {
String translationKey = "ENUM_NAME." + getComponent().getEnumValue();
IController controller = (IController) lifecycleHandler;
return controller.getTranslation(translationKey, controller.getLocale());
}
Just remember that the pattern for the I18N resource bundle key of enumerations is ${ENUM_NAME}.${ENUM_VALUE} which is computed as the translationKey local variable in the code above.

Swift: Computed type properties in classes

I'm trying to understand something about type properties in swift.
The Swift Programming Language says
For classes, you can define computed type properties only
So a computed property does not store a value itself, but it is calculated. That I understand. But I don't get how such a thing can apply to type properties. Such properties belong to the class itself and not to an instance of it.
So if you use a getter for such a computed type property, what could you possibly use to calculate it? It can't be any other type properties, as they too can only be computed properties. You would get a sort of loop of computed properties because there aren't any stored type properties.
In the same way, I also don't get what a setter would do. If you call the setter of a computed type property, what can it set? There are no stored type properties to be set.
Bear in mind that stored class properties are only unsupported at the moment. The compiler error you get when you try to use them—"Class variables not yet supported"— suggests that they're on their way. Computed class properties don't necessarily have to make sense on their own.
However, computed properties don't always have to be based on the values of stored data. As it stands, you could use them for "static" read-only values associated with the class, say:
class var ThisIsAClassConstant: String { return "Woo" }
And people have already come up with ways to store associated values, for example, in the first two singleton patterns in this answer, the class property stores its state in either a global (but private) variable, or in a static variable inside a nested structure.
These are obviously a bit "workaroundy", but they're a way of achieving class-like storage while it's not officially implemented.

Is there any good reason to use 'id' as return type or parameter type in public API?

I am learning from Stanford's CS193P course. In the class, Paul has a demo project, "Calculator", where he uses id as the type of a property. He intends to not use a specific class, because he does not want to create a new class and then he does not need to write documentation, and even when it is updated, he does not need to redesign the class. id can solve all these problems.
Is this a really a good way? id is the return type of the property, and used as the parameter type of another method. How does the caller know what id is, and how to provide the correct object? By reading code comments?
In general, is there any good reason to use id as a return type or parameter type in public API? (Except init and factory method, though even for those, instancetype is recommended.)
If your method returns a class that is a member of a class cluster, you should return id.
If you're returning an object whose class is opaque, isn't declared in a public header, you should return id. (Cocoa occasionally uses such objects as tokens or context data.)
Container classes should always accept and return their constituents as ids.

CF9 ORM Populating an entity with an object

I am using Model-Glue/Coldspring for a new application and I thought I would throw CF9 ORM into the mix.
The only issue I am having right now is with populating an entity with an object. More or less the code below verifies that only one username can exist. There is some other logic that is not displayed.
My first thought was to using something like this:
var entity = entityload('UserAccount' ,{UserName=arguments.UserAccount.getUserName()},"true")
entity = arguments.UserAccount;
How ever this does not work the way that I expected. Is it even possible to populate an entity with an object or do I need to use the setters?
Not sure if this is what you're looking for. If you have...
component persistent="true" entityName="Foo"
{
property a;
property b;
}
You can pass a struct in the 2nd param to init the entity (added in CF9.0.1 I believe)
EntityNew("Foo", {a="1",b="2"});
To populate Foo with another object, you can use the Memento pattern, and implement a GetMemento() function to your object that returns a struct of all its properties.
EntityNew("Foo", bar.getMemento());
However, CF does NOT call your custom setters! If you want to set them using setters, you may add calls to the setters in your init() constructor, or use your MVC framework of choice to populate the bean. In Model-Glue, it is makeEventBean().
Update: Or... Here's hack...
EntityNew("Foo", DeserializeJSON(SerializeJSON(valueObject)));
Use this at your own risk. JSON might do weird things to your numbers and the 'yes','no','true','false' strings. :)
Is it even possible to populate an entity with an object or do I need to use the setters?
If you mean "Is it possible to create load an ORM Entity from an instance of that persistent CFC that already exists and has properties set?", then yes you can using EntityLoadByExample( object,[unique] )
entity = EntityLoadByExample( arguments.userAccount,true );
This assumes the userAccount CFC has been defined as persistent, and its username value has been set before being passed in (which seems to be the case in your situation).
Bear in mind that if any other properties have been set in the object you are passing, including empty strings, they will be used as filters to load the entity, so if they do not exactly match a record in your database, nothing will be loaded.