Post-Initialization in extbase domain model - typo3

In one of my extbase models, I want to initialize some properties derived from the properties that are saved in the database. The computation of these virtual properties is time consuming, so I'd like to cache them. Thus my program flow should look somehow like this:
Load the domain object as usual from the database
Check if the virtual property is available in cache. If so, fetch it from there, otherwise compute and cache it.
I first thought the method "initializeObject" is what I need, but it is not: It is called before any property is initialized from the database. So I came up with two other ways:
I can call an initialization-method manually from the repository after fetching the object, but that seems weird and would break if someone adds another find* method to the general repository.
Another idea is to add a boolean "virtualPropertiesInitialized" to the model, query it whenever one of the virtual properties is accessed and initialize the virtual properties if needed. Also seems weird, but would not break if someone adds another "find"-method to the generic repository.
My question is:
Is there a default/best-practice how to do what I want to do?

If reading the final value from disk or database is less computationally intensive, then store the value using the TYPO3 caching framework or by your own caching method of a static class and restore it in the getter of the virtual property. Doing it in the getter method public mixed getYourPropery() will give you the feature that the value is only get from the cache when you call it.
On the second call, just return the value you stored previously:
private $myValue = NULL;
public function getMyValue() {
if($this->myValue != NULL) return $this->myValue;
$this->myValue = "test";
return $this->myValue;
}

Related

Spring Caching and hard coded cache name

I am using spring caching in my project using annotations. Based on profile I am using Elasticache and SimpleCacheManager. The annotations used are
//For the initial configuration settings in some class when profile is cloud.
#EnableElastiCache({#CacheClusterConfig(name = "MyCache", expiration = 86400)})
// For the initial configuration settings in some class when profile is non-cloud.
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
simpleCacheManager.setCaches(newArrayList(new ConcurrentMapCache("MyCache")));
#CacheConfig(cacheNames = {"MyCache"})
public class CachingRequiredClass{
........
#Cacheable
public String blablaMethod(String id){
.....
}
}
public class SomeOtherClass{
......
#Caching(evict={
#CacheEvict(value="MyCache", key="T(com.myclass).myMethod()+':blablaMethod()'"),
#CacheEvict(value="MyCache", key="T(com.myclass).myMethod()+':blablaMethod()+':blablabla2Method()'")
})
public void logout(){
......
}
}
I am forced to hard code cache name "MyCache" everywhere which I dont like. Is there a way to make this configurable. Somehow coming from a property file??
You have several options.
First of all, it is Java so you can create a constant somewhere and refer to it. Then those places allow for SpEL so you can write ${myCache} and have a myCache property in the environment that has the value of your cache.
Finally, rather than specifying the cache names in code (be it using SpEL or not) you can implement CacheResolver and decide which cache to use programmatically. It's more work and probably overkill if you don't need to change the cache to use according to some business logic.
Part of the smell it annoys you is that you are maybe using the same cache for too many things. That key attribute in your last example looks mental to me: if you need to add the name of the class and the method to the key, it tells me you're trying to put way too many things in the same cache. You shouldn't design your cache like that: do not forget it is just a shortcut so that you don't have to do this manually. If you want to query the cache for a value, are you seriously going to use the name of the class and the method to compute the key?

How to access the value of a Property argument from nested activities?

I'm sure there's something I'm missing here, but a lot of Googling hasn't uncovered it for me. The situation is like this:
We created a custom workflow designer that allows end users to build workflow definitions from various custom activities we define (Review, Submit, Notify, etc). These definitions (Xaml) get saved off to a Db and used to create workflow instances for long running processes in our system. The users can set properties on each of them (e.g. Review has a property argument: AllowedRoles). The problem is, I'm not able to pass those properties on to nested activities.
For example:
Review has an internal activity 'WriteStatus' that needs access to the 'AllowedRoles' property on Review. If 'AllowedRoles' is defined as a Property, WriteStatus can't "see" it to assign it's value. I can change it from a Property to an InArgument, but then I'm not able to map values to and from the property in the designer (these properties should be part of the definition, and not associated with any specific context).
Has anyone faced this issue or have advice on how I could approach the problem differently?
Thanks in advance!
Royce
I was able to get around the property vs InOurArgument problem by converting the XAML activities to code. This allowed me to set the properties on activities in code, and then pass them to inner activities inline. There may be a better way, but it's working out well so far.
public sealed class Test : Activity
{
public string Stuff { get; set; } // CLR Property
public Test()
{
Implementation = () => new WriteLine {Text = Stuff};
}
}

Zend Framework: Models, Mappers; Default Fields in Mappers & Field Operations in Models?

I'm creating a simple ORM in Zend Framework, to roughly encapsulate a public library application, using the DbTable/Mapper/Model approach. I'm not sure if the way I'm doing my User-related classes is right, though, as I have some logic in Mapper_User, and some in Model_User.
Mapper_User
<?php
class Mapper_Users {
/*
createModelObject would be called by a Controller handling a Form_Regsiter's
data, to create a new Model_User object. This object'd then be saved by the
same Controller by calling Mapper_Users->save();
*/
public function createModelObject(array $fields) {
if(!isset($fields['date_registered']))
$fields['date_registered'] = date('Y-m-d H:i:s');
if(!isset($fields['max_concurrent_rentals']))
$fields['max_concurrent_rentals'] = 3;
return new Model_User($fields);
}
}
?>
In the method which creates new Model_User objects from scratch (as in, not pulling a record from the DB, but registering a new user), I instantiate a new Model_User with the name/username/password provided from a Form, then set a few object properties such as the registration date, "max books allowed at one time" and such. This data, being stuffed inside the Model_User by the Mapper_User, then gets written to the DB when Mapper_User->save(); gets called. The Mapper feels like the right place for this to go - keeps the Model light.
Is this right, or should default fields like this be set inside Model_User itself?
Model_User
<?php
class Model_User {
public function setPassword($value) {
$this->password = md5($value);
}
}
?>
When setting a user object's password, I'm doing this in Model_User->setPassword($value);, as you might expect, and doing $this->password = md5($value); inside this method. Again, this feels right - trying to do the md5 step in Mapper_User->save(); method would cause issues if the Model_User were one pulled from the DB, as the password field would clearly already be hashed.
And this is where my confusion's arising. To my mind, all the logic pertaining to "fields to do with a user" should either live in its Model, or its Mapper, but here I have some logic (default fields) in the Mapper, and some (field operations) in the Model. Is this right, or should I be trying to somehow get default fields in the Model, or field operations in the Mapper?
Thanks for taking the time to read this!
Edit for #RockyFord:
Mapper_User actually extends an Abstract I've written, as I don't like writing the same basic code in 500 Mapper_*.php files, so there's some bureaucracy due to that, but its effective __construct() is pretty simple:
<?php
class Mapper_Users {
public function __construct() {
$this->_db = new DbTable_Users();
if(!$this->_db instanceof Zend_Db_Table_Abstract)
throw new Exception('Invalid table data gateway provided');
}
}
?>
The DataMapper is responsible for populating the object with its data, as well as persisting it. It seems like you're mixing things when you call $user->save() because you're putting persistence logic within your domain object. This is a common approach when you're using the ActiveRecord pattern instead of DataMappers, which is a bad thing.
Your DataMapper should be responsible for saving the object $mapper->save($user); and it needs to update just the changed properties. So, the password will be updated only if you set the new hash.
UPDATE:
You said:
[...] trying to do the md5 step in Mapper_User->save(); method would cause
issues if the Model_User were one pulled from the DB, as the password
field would clearly already be hashed.
Creates a method called setPasswordHash() and use it when pulling from the database.
Remember: Don't look for things!
Instead of looking for the database inside your mappers, you should ask for it.
public __construct(Zend_Db_Table $dbTable) {
$this->dbTable = $dbTable;
}
It's all about Dependency Injection.
This may take awhile to answer completely but I'll start with the setPassword question.
your current:
public function setPassword($value) {
$this->password = md5($value);
}
Now this has nothing to do with convention or best practice but practicality.
ask yourself:
What happens when you retrieve a database record for your user object and that database record contains a hashed password?
Answer: When you construct the user object and call $this->setPassword($password); or equivalent, you will be applying the hash to a hash.
So you are almost obligated to hash the password in the mapper's save() method or the method used to update the password. Think of the hash value in the database table as the password and the value that's typed into the form field as a placeholder for that password.
Next Part:
To my mind, all the logic pertaining to "fields to do with a user" should either live in its Model, or its Mapper
This is mostly correct.
Everything that belongs to the object domain (Model_User) shall be addressed in the domain Model class (Model_User).
Mappers are only to translate (map) a data object (database row, json string, xml file, flat file, csv file ...) to a form that can instantiate a domain object (Model_User).
So you may end up with more then one mapper available for a given domain object or one mapper may map to more then one source of data.
It might help you if you stopped thinking of your data as "fields", which might tend to keep your head in the database, and instead think of your objects in terms of properties or characteristics.
Because when you get down to the most basic level a Model_User object is just:
class Model_User {
protected $id;
protected $name;
protected $password;
//continue....
}
all of the getters, setters, constructors and other methods are pretty much so we can put values into those variables.

How do you create a FubuMVC behavior that copies site configuration values to an output model?

I'm trying to figure out to create a behavior that will copy a boolean site configuration value to an output model.
This way I don't have to copy the bool in each action who's view requires it, but can simply add the behavior to the controller actions that need this value.
In some of the older versions of FubuMVC, I believe behaviors could modify the output model after it's left the controller. But I'm not sure how to do this in the more recent versions of FubuMVC (or I've forgotten).
Can anyone give me an example of or point me in the direction of the best practice for copying a site configuration value to an output model?
Let's say I had an output model called HomeViewModel that had a property called FooterText that I wanted loaded from settings object (let's say HomeSettings) that was retrieved from the container (i.e. StructureMap).
The Behavior
My behavior would look something like this:
public class HomeFooterBehavior : BasicBehavior
{
private readonly HomeSettings _settings;
private readonly IFubuRequest _request;
public HomeFooterBehavior(HomeSettings settings, IFubuRequest request)
: base(PartialBehavior.Executes)
{
_settings = settings;
_request = request;
}
protected override DoNext performInvoke()
{
SetupFooter();
return DoNext.Continue;
}
public void SetupFooter()
{
var viewModel = _request.Find<HomeViewModel>().First();
viewModel.HomeFooterText = _settings.FooterText;
}
}
This behavior takes in the HomeSettings object and the IFubuRequest object (both injected dependencies) and then gets the HomeViewModel (output model) from the request and then sets the HomeFooterText property on the output model based on the value from the settings object.
NOTE: I'm assuming that you've already got your HomeSettings object wired up in the container (for example, using the ISettingsProvider stuff built into FubuMVC). If you don't already have this, let me know and I can post some code on how to do that.
Wiring Up The Convention
To wire up the behavior, you'll need to define the convention through an IConfigurationAction, for example:
public class HomeFooterBehaviorConfiguration : IConfigurationAction
{
public void Configure(BehaviorGraph graph)
{
graph.Actions()
.Where(x => x.HasOutput &&
x.OutputType().Equals(typeof(HomeViewModel)))
.Each(x => x.AddAfter(Wrapper.For<HomeFooterBehavior>()));
}
}
This is a real dumb convention for demonstration purposes. In your project, you might make it a little more generic. For example, any output model that has an attribute on it, or implements a specific interface, etc. In fact, you might want to inspect all output models to see if they contain any properties that match a certain criteria (for example, all properties that end with "Settings" - like "FooterSettings" or something).
Don't be afraid to define wide sweeping conventions like this due to performance concerns since all this convention code runs at start-up time and not on every request.
Note the "AddAfter" call and the "Wrapper.For" call. That's the key in that it places your behavior after the controller action is executed, but before the view is rendered.
Now that you have your behavior and your convention defined, it's time to wire it up in your FubuRegistry.
Wiring Up Your Convention in your FubuRegistry
After the call to "Routes." in your FubuRegistry, add a line like this:
ApplyConvention<HomeFooterBehaviorConfiguration>();
Recompile and it should work.
Please let me know if you run into any problems.

Entity Framework Validation & usage

I'm aware there is an AssociationChanged event, however, this event fires after the association is made. There is no AssociationChanging event. So, if I want to throw an exception for some validation reason, how do I do this and get back to my original value?
Also, I would like to default values for my entity based on information from other entities but do this only when I know the entitiy is instanced for insertion into the database. How do I tell the difference between that and the object getting instanced because it is about to be populated based on existing data? Am I supposed to know? Is that considiered business logic that should be outside of my entity business logic?
If that's the case, then should I be designing controller classes to wrap all these entities? My concern is that if I deliver back an entity, I want the client to get access to the properties, but I want to retain tight control over validations on how they are set, defaulted, etc. Every example I've seen references context, which is outside of my enity partial class validation, right?
BTW, I looked at the EFPocoAdapter and for the life of me cannot determine how to populate lists of from within my POCO class... anyone know how I get to the context from a EFPoco Class?
This is in reply to a comment I left. Hopefully this answers your question, Shimmy. Just comment, and I will shorten it or remove it if it doesn't answer your question.
You will need both INotifyPropertyChanging and INotifyPropertyChanged interfaces to be implemented on your class (unless it is something like an entity framework object, which I believe implements these internally).
And before you set a value to this property, you will need to raise NotifyPropertyChanging.PropertyChanging event, using the name of the property in PropertyChangingEventArgs constructor.
And after you set this value you need to raise NofityPropertyChanged.PropertyChanged event, again using the name of the property this is being raised in PropertyChangedEventArgs constructor.
Then you have to handle the PropertyChanging and PropertyChanged events. In the PropertyChanging event, you need to cache the value. In the PropertyChanged event, you can compare and throw an exception.
To get the property from PropertyChanging/PropertyChanged event args, you need to use relfection.
// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it checks if e.PropertyName already exists.
propertyDict.Add(e.PropertyName, propertyValue);
} // End PropertyChanging() Event
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it makes sure e.PropertyName exists.
object oldValue = propertyDict(e.PropertyName);
object newValue = propertyValue;
// No longer needed.
propertyDict.Remove(e.PropertyName);
if (/* some condition */)
{
try {
preventRecursion = true;
info.SetValue(oldValue, null);
Throw New Exception();
} finally {
preventRecursion = false;
} // End try
} // End if
} // End PropertyChanging() Event
Notice how I am using PreventRecursion, which is a boolean I forgot to add above these methods? When you reset the property back to its previous value, these events will be recalled.
tl;dr
Now you could derive a single event which inherits from INotifyPropertyChanged, but uses an argument which holds an Object representing the previous value as well as the Property Name. And that would reduce the number of events being fired down to one, have similar functionality, and have backwards compatibility with INotifyPropertyChanged.
But if you want to handle anything before the property gets set (say the property does an irreversible change or you need to setup other properties before setting that variable, otherwise an exception will be thrown) you won't be able to do that.
Overall, this method is a very old way of doing things. I would take Poker Villian's answer and have invalid data able to be entered. But disallow saving to a database.
Entity Framework has some excellent code towards validation. You add validation to your properties via attributes. And then it takes care of the work of processing those attributes. Then you can make a property called IsValid, which calls Entity Framework specific validation. It also distinguishes both field errors (like typing in the wrong characters or having a string too long), and class errors (like having missing data or conflicting keys).
Then you can bind IsValid to controls validation, and they will display a red bubble while invalid data is entered. Or you could just implement IsValid validation yourself. But If IsValid is false, SaveChanges event would need to cancel saving.
btw. The code provided will not compile and is pseudocode only (mixing vb and c#). But I believe it is much more descriptive than c# alone--showing exactly what is being handled.
Concerning your first question, I would simply implement the changes to the associations as business logic. For example, if you add a Teacher class with multiple Student, do not add students like
aTeacher.Students.Add(new Student)
instead, create a AddStudent method
public Student AddNewStudent(string name, string studentID)
{
Student s = new Student( name, studentID);
s.Teacher = this; // changes the association
return s;
}
That way you have full control on when associations are changed. Of course that what prevents another programmer from adding a student directly? On the Student side, you can set the Teacher setter to private (and change the constructor to accept a teacher or similar). On the teacher side, how to make the Students collection non-insertable? I'm not certain... maybe transforming it in a custom collection that doesn't accept inserts.
Concerning the second part of your question, you could probably use the OnVarNameChanging events. If the EntityState is 'New' then you can apply your logic that fetches the real values.
There is also an event that fires when you save changes (OnSavingChanges?) that you could use to determine which objects are new and set some values.
But maybe the simplest solution is to always set the defaults in the constructor and they will get overwritten if the data is loaded from the DB.
Good luck
Create a factory that produces instances for you depending on your need like:
getStudent(String studentName, long studentId, Teacher teacher) {
return new Student(studentName, studentId);
}
getStudentForDBInseration(String studentName, long studentId, Teacher teacher) {
Student student = getStudent(studentName, studentId);
student = teacher;
//some entity frameworks need the student to be in the teachers student list
//so you might need to add the student to the teachers student list
teacher.addStudent(student);
}
It's a serious lack not having an AssociationChanging (that inherits from CancelEventArgs) event.
It bothers me also very much, therefore I reported this to Microsoft Connect Please vote here!
And BTW, I also think this is also stupid that the PropertyChangingEventArgs doesn't inherit CancelEventArgs, since cancelling with an exception is not always the elegant solution, besides, throwing exceptions cost more performance than calling the OnPropertyChangingEvent then check for the returned e.Cancel, so does it cost less than raising the PropertyChangingEvent, which you anyway call them both.
Also an exception can be thrown at the handler anyway instead of marking e.Cancel as true, for those who insist to go the Exception way. Vote Here.
To maybe answer part of your question or expound on ADB's answer you can user ObjectStateManager.GetObjectStateEntry to find the state of the entities and write your custom default logic.
SaveChanges is the method on the context that you can use, or SavingChanges is the event that occurs before SaveChanges is called.
You can override SaveChanges and only call base.SaveChanges if you don't want to abort the change
There is also a ObjectMaterialized event for the context.
Between the two you can stick all your validation and creation code in one location, which may be appropriate if they are complex and include values of other objects etc..