How to extend an activeRecord model in Yii - yii

I'm trying to create a form in Yii that is paged. Each page is for a group of fields. The best way to do this, I figured, would be to extend the ActiveRecord model and add a parameter for the current page. This also allows me to override the rules() methods with my own rules for the form itself.
My problem with this is, Yii doesn't allow us to natively extend models. I had to override the getMetaData() method because Yii runs self::model(get_class($this)) on itself, which ends up breaking everything.
Not only that, but I can't use findByPk because Yii relies heavily on the class name.
I know of tons of work arounds to make this work, but I'm wondering if I'm missing something.
Thanks,
Kyle
-- edit --
I totally figured it out, and I totally feel stupid. All I had to do with overwrite the model() method to return the current model class.
So:
class MyAr extends CActiveRecord {
public static function model($class = __CLASS__){return parent::model($class);}
}
class ExtendedForm extends MyAr {
public static function model($class = __CLASS__){return parent::model($class);}
}
Yeah ... I feel stupid.

To extend an ActiveRecord model, simply extend it! All you need to do is override the model method:
class MyAr extends CActiveRecord {
public static function model($class = __CLASS__){return parent::model($class);}
}
class ExtendedForm extends MyAr {
public static function model($class = __CLASS__){return parent::model($class);}
}

The model classes are subclasses of ActiveRecord, so you can override some vars/methods of ActiveRecord whitin them. What I mean is that there's no need to extend Activerecord... again! It is extended when defining models! So just add what whatever you need in there. Of course, this way has the inconvenience of adding the code manually in every model class. If it is too much, and if you're using gii, then you could just modify the code template that gii uses to generate the models.

Related

Extending vs Re-instantiating

I'm wondering which of the following two methods would be more efficient, or if it doesn't actually matter which route you take as the overhead is minuscule.
Essentially, is it better to instantiate a class (for example, 'Db') that you know is going to be used often in a parent class and simply extend the parent class whenever you want to use 'Db', or is it better to instantiate 'Db' separately in the constructor of the classes you want to use it.
Obviously the best route to take in terms of avoiding duplicate code would be to instantiate it in a parent class but just out of curiosity I was wondering if anyone has any insight into how significant/insignificant the effect on the server is for these two routes.
Route 1:
// Parent
class template {
public function __construct() {
$this->db = new Db();
}
}
// Child
class login extends template {
public function __construct() {
// Has access to $this->db
}
}
Route 2:
class login {
public function __construct() {
$this->db = new Db();
}
}
Thanks in advance.
It shouldn't matter performance wise.
If you extend the template class, you still have to instantiate the child class, which in turn will call the constructor of the parent implicitly. This means that in both cases, the DB class will be instantiated. Even worse, the extended class will probably be a little bit slower because it has the added overhead of an extra function call (that of the parent construct method).
That being said I strongly recommend to read up on composition over inheritance. Parent child relations are there to enforce an "is a" relationship. If you start extending the same class simply for performance reasons, chances are you are going to shoot yourself in the foot later on. It is simply unexpected behavior for most programmers to have unrelated classes extend from the same parent.

How do I create hypermedia links in custom serializer with Spring Data Rest

I have a abstract class and two implementations:
public abstract class Attribute {
// some properties
}
public class CustomAttribute extends Attribute{
private String property1;
}
public class DefaultAttribute extends Attribute{
private String property2;
}
There's another class, which includes these attributes:
public class Step{
private List<Attribute> attributes;
}
Now when Step gets serialized, the self link is missing. I need the self reference, since I want to update the attributes. According to the documentation, jackson needs a little help deciding which class to use. But that does not help, because I need to use both classes. So I build a custom serializer (and registered with a module) for Step and now I wonder how I can construct the link myself. I couldn't find anything in the Spring Data Rest docs regarding this. Since Spring Data Rest adds these links automatically, I think there might be a way to have the protocol/hostname/port information available in the JsonSerializer. How do I get the information in my custom serializer?
Ok, now I use the linkTo() function to get the hostname and port and I manually set the rest of the resource URL in my custom serializer.
final Link attributeLink = linkTo(CustomAttributeRepository.class)
.slash("/api")
.slash("customAttributes")
.slash(attribute.getIdentifier()).withSelfRel();
//#formatter:off
jsonGenerator.writeFieldName("_links");
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("self");
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("href", attributeLink.getHref());
jsonGenerator.writeEndObject();
jsonGenerator.writeEndObject();
//#formatter:on

Base class for common YII functions?

I know how to create a class the will allow me to instantiate it and use across my project. What I want to be able to do is have functions without instantiating classes. For example, I know how to do this:
$core = new core();
$val = $core->convertToMyNotation($anotherval);
But what I want is to be able to do this ANYWHERE in any view, class whatever:
$val = convertToMyNotation($anotherval);
Where would I place these functions in order to be able to do that?
best way to do it, create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
You can define a static method as an option.
class core{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
Then call it like so:
$val = core::convertToMyNotation($anotherval);
This requires no instantiation of the object to use. The only restriction is that you cannot use the $this property inside a static method.
Alternately, just define a file with your functions in it and include the file at some point early like, like within the boostrap script in your public_html/index.php file.
Edit: darkheir makes some good suggestions. Include such a class in your protected/components folder, and have it extend CComponent to gain some potentially useful enhancements.
By including the class in the protected/components folder, you gain the advantage of autoloading the class, by default.
There is no definitive question of your answer, it depends a lot on what the function will be doing!
If the function is performing some things specific to a model
(getting the last users, ...) this has to be in the User model as
Willem Renzema described:
class theModelClass {
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And you'll call it like
$val = theModelClass::convertToMyNotation($anotherval);
If the function is handling user inputs (sanitizing he inputs,
checking the values, ...) then it has to go to the controller and
you'll use Hemc solution:
Create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
If the function is an Helper: performing some actions that do not
depend on models or user inoput then you can create a new class that
you'll put in your component directory:
class core extends CComponent{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And
$val = core::convertToMyNotation($anotherval);
Actually, I think you're looking for this answer instead:
http://www.yiiframework.com/wiki/31/use-shortcut-functions-to-reduce-typing/
In essence, in your entry script, before you load up Yii, include a global functions file:
require('path/to/globals.php');
Then, any function defined in that file can be used as a shortcut. Be careful, but enjoy the power! :-)
Create something like
Class Core extends CApplicationComponent{
public function doSomething(){}
}
and in config main.php
'components'=>array(
'core'=>array(
'class' => 'Core'
),
),
and now you can call whenever you want
Yii::app()->core->doSomething();

Building one object given another

Say I am calling a third-party API which returns a Post, and I want to take that and transfer properties from it into my own Post class. I have in the past had a method like public static my.Post build(their.Post post) which maps the properties how I want.
However, is it better/valid to have a constructor that accepts their.Post and does the property mapping in there? Or should there always be a separate class that does the converting, and leaves my.Post in a more POJO state?
Thanks for your thoughts!
These answers always starts with "it depends."
People generally argue against using public static methods, based on the fact that it is hard to mock them (I don't buy into that bandwagon).
This comes down to design, do you want their post to be part of your class? If you add it as a "copy" constructor then it will now be part of your class and you are dependent on changes to post. If they change their post, your code has to adapt.
The better solution is to decouple it. You would need to find some extenal method to map the two. One way is to use a static builder method (like you mentioned) or if you want to take it a step further, a more complicated solution would be to extract the information you want from their post into some type of generic collection class. Then create a constructor that will accept that constructor class. This way if they change their design your class stays in tact and all you have to do is update the mappings from their post to your generic representation of it.
public class MyPost{
public MyPost(ICollectionOfProperties props){
//copy all properties.
}
}
public static class TheirPostExtensions{
public static ICollectionOfProperties ExtractProperties(this TheirPost thePost){
return new CollectionOfProperties(){
A = thePost.PropA,
B = thePost.PropB
};
}
}
public class Example{
public Example(){
TheirPost tp = new TheirPost();
ICollectionOfProperties props = tp.ExtractProperties();
MyPost mp = new MyPost(props);
}
}

AutoMapping Custom Collections with FluentNHibernate

I am retrofitting a very large application to use NHibernate as it's data access strategy. Everything is going well with AutoMapping. Luckily when the domain layer was built, we used a code generator. The main issue that I am running into now is that every collection is hidden behind a custom class that derives from List<>. For example
public class League
{
public OwnerList owners {get;set;}
}
public class OwnerList : AppList<Owner> { }
public class AppList<T> : List<T> { }
What kind of Convention do I have to write to get this done?
I don't think you're going to be able to achieve this with a convention. You will have to create an auto mapping override and then do the following:
mapping.HasMany(l => a.owners).CollectionType<OwnerList>();