I'm just a newbe in Kohana ORM, so my question may be a bit silly for pro's, but.. :)
I have some ORM models, and all of them have a few the same methods like:
public function items_order_by_id($reverse = false)
{
if($reverse) return $this->order_by($this->_primary_key, 'desc')->find_all();
else return $this->order_by($this->_primary_key, 'asc')->find_all();
}
OR
public function get_form()
{
$result = array();
foreach($this->_table_columns as $key => $value)
{
if($value['form']) $result[$key] = $this->_prefix.'_'.$key;
}
return $result;
}
If I'm adding a new model I must copy all similar methods, and If I want to modify any method I must modify all files. I know object programming has inheritance, but when I'm trying to extend Kohana_ORM I get exception for example:
The comment_id property does not exist in the Model_Comment class
And all another properities also do not exist.
Is it possible, to have a parent model which contain these methods?
Yes it is possible. You just have to make sure you write your functions so that they can be used by all Other models that will be extending it.
Most likely you are setting variables that don't exist for the Model you are running. That is why it's throwing errors.
Also this is a bit offtopic but you should take a look at AutoModeler. If you want a flexible Model system. https://github.com/zombor/Auto-Modeler
It has about the same functions as ORM but makes extending a lot easier.
Oh, It was definitely silly.
I have just override _construct function and forgot parent::_construct().
So the problem is solved and now everything is ok.
Sorry for that :)
Related
I know what dependency injection is and why to use it (it's better to inject class than to use new keyword because it's kind of makes impossible to test it later). I'm going to talk about Laravel's ways of how to write controllers.
Way 1)
Let's say I have the following function in controller and I want to test it.
public function index() {
$allActors = \App\Actor::all();
foreach($allActors as $actor){
$actor->name="gio";
}
return $allActors;
}
As you see, controller and model is tightly coupled. My question is why I can't test this method? I looked through Laravel's mockery and I think it could be tested. What I'd do is before making a call to index method, I'd mock the \App\Actor and what it should return. Why shouldn't I follow this idea?
Way 2)
protected $actor;
public function __construct(\App\Actor $actor){
$this->actor = $actor;
}
public function index() {
$allActors = $this->actor->all();
foreach($allActors as $actor){
$actor->name="gio";
}
return $allActors;
}
Now you think this could be tested? how? One thing I can think of is before creating new controller, I'd create new class that extends Actor model and override its functions, in this case all() function and get the results from file.
The main question is why can't I test it in the first example and in the second example? Which one is better for DI? It seems like the second option is DI, but I looked through Laravel's docs and I think the first example can be mocked still. But I also read that Eloquent models can't be mocked. I am seeking a whole idea about all of this.
I have a simple requirement where I want to allow a Class (Laravel Model) to define whether a controller should check whether it's allowed to be deleted or not based on a class variable like so
public $verify_delete = true;
Currently if this variable is set I must add the following method;
public function deletable()
{
$deletable = true;
if ($this->has_children()) {
$deletable = false;
}
// ...
return $deletable;
}
The first variable is simply an indication the code running this class should also run the deletable() method.
So what I want is a way to force a developer to implement the deletable() method if they set the $verify_delete to true, and throw an error if they have not done so. I don't know much about traits and implements at this stage, so I'm not sure if they're the right route to go down.
If this is not the best method to achieve what I'm after I'm all ears.
You should create a trait called Deletable or Removeable or something along these lines and implement this delete method there and then each model that can be deleted will use this trait. Not exactly what you wanted but it is the right approach.
Or
You can create an interface which will have this method inside and then each class (model) which implements this interface will have to implement the method, the only difference is that implementation may vary depending on the model from others
You question is this: can I detect if a method is callable in a class, when a specific property is set...
Other (very wise) solutions are suggesting interfaces and traits... A perfectly fine idea and a really good way to look at things.
But you can think of something like this as well:
public function __construct() {
if (true === $this->verify_delete && !method_exists($this, 'deletable')) {
throw new \Exception('Hi developer! You forgot something...');
}
}
Explanation:
on the constructor you check if the property is true.
if the method does not exist, let's throw an exception
I think this does exactly as you ask: force the developer to implement the deletable method, when the property is set.
But to be honest, I really like those traits as well... I just wanted to give you an alternative that does the trick as well if you are not too comfortable with techniques likes interfaces, traits, etc.
I'm setting up a new section of a framework I've inherited. It's a chance to really enforce some best practice, so I'm trying to do as much as possible.
The framework is running in php5.4 (windows environment).
I've set up an abstract class, BaseModel. In this I define several core bits of functionality, for example: common accessors and common db interaction.
I then extend this to create the models I'll be using. In the test case the file "UserModel" creates a class called "User" .
In BaseModel I'm creating the following abstract function:
abstract public function getById($id);
Within the UserModel I then define this function
public function getById($id)
{
// just a test!
return 'this works!';
}
I would like to enforce typesafeing. However I get errors if I do anything like this:
public function getById(User $id)
{
// just a test!
return 'this works!';
}
I can do the following
abstract public function getById(BaseModel $id);
public function getById(BaseModel $id)
{
// just a test!
return 'this works!';
}
Which works, but is also a bit less useful to be honest. A User is of type BaseModel, but so would every other extended class be. What I want to do is this:
abstract public function getById(BaseModel $id);
public function persist(User $item)
{
// just a test!
return 'this works!';
}
I know I can add in a line doing manual typesafing, along these lines (pseudocode)
if ($item instanceof User)
{
//do stuff
}
However - this seems to be a bit of a work around, as opposed to finding the true approach.
I have a sinking feeling that this kind of "smart/aware class" feature isn't available in php.
Can anyone confirm/deny this or provide a more elegant work around?
Having done a bit more digging around, and thanks to a helpful post from deceze, I think this idea hasn't been implemented. He has pointed out a similar answer it to which breaks the rules of SOLID.
http://en.wikipedia.org/wiki/SOLID
Basically - This says that I cannot change the parent class: this is the point of "extend".
I can only extend, not modify the parent class.
Changing the typesafeing is modifying the class.
HOWEVER - I would argue that this example doesn't break the rules of SOLID.
Typesafing with class that is extended from the base class should be allowed: You can never have a "User" that is not a "BaseModel"... so it is not modifying the parent class.
It looks like the only way to truly do this is
if ($item instanceof User)
{
// logic
}
In my case the parent class is probably enough to catch most issues, but it's a shame I can't typesafe it the way I intended.
[Thanks to deceze. Upvoted.]
I was trying to find a way to execute some code to alter the results of an objects methods without actually touching the object's code. One way I came up is using a decorator:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
That way it will work properly but it has one disadvantage which makes it unusable for me right now - it would require replacing all lines with new Test() with new Decorator(new Test()) and this is exactly what I would like to avoid - lots of meddling with the existing code. Maybe something I could do in the base class?
One does not simply overload stuff in PHP. So what you want cannot be done. But the fact that you are in trouble now is a big tell your design is flawed. Or if it is not your code design the code you have to work with (I feel your pain).
If you cannot do what you want to do it is because you have tightly coupled your code. I.e. you make use of the new keyword in classes instead of injecting them (dependency injection) into the classes / methods that need it.
Besides not being able to easily swap classes you would also have a gard time easily testing your units because of the tight coupling.
UPDATE
For completeness (for possible future readers): if the specific class would have been namespaced and you were allowed to change the namespace you could have thought about changing the namespace. However this is not really good practice, because it may screw with for example autoloaders. An example of this would be PSR-0. But considering you cannot do this either way I don't see it is possible what you want. P.S. you should not really use this "solution".
UPDATE2
It looks like there has been some overload extension at some time (way way way back), but the only thing I have found about it is some bug report. And don't count on it still working now either way. ;-) There simply is no real overloading in PHP.
Found something (a dead project which doesn't work anymore that enables class overloading): http://pecl.php.net/package/runkit
Possibly another project (also dead of course): http://pecl.php.net/package/apd
I am not a PHP programmer, but I think that AOP is what you are looking for. You can try some frameworks, for example listed in this answer.
From the Wikipedia article on the decorator pattern:
Subclass the original "Decorator" class into a "Component" class
So I think you're supposed to keep the class to be decorated private and expose only the already-decorated class.
I need some advice on how I can proceed with this issue.
Using PHP
An example would be:
class BuilderClass {
function getClass($id, $some, $vars){
$dbResult = new db_Class::getDbRows($id, $some, $vars);
foreach(...)
// Build something from the database values
return self;
}
}
So what I want to do is to create a test case where I somehow mock the db results.
I have not found any great way to do this, please point me in the right direction or similar to get this working for me.
I could change something within the builder itself for example call a class that runs the function: FunctionRunner::runStaticFunction("db_Class", "getDbRows", $args, $something_else); But at the moment I don't know if that is possible neither. Any research articles that cover this or any sites that explain this. I'd appriciate anything at the moment.
Thanks
/Marcus
Split the operations of retrieving data from database, and building the data.
class BuilderClass {
function getClass($id, $some, $vars){
$dbResult = new db_Class::getDbRows($id, $some, $vars);
return doGetClass($dbResult);
}
function doGetClass($dbResult) {
foreach(...)
// Build something from the database values
return self;
}
}
That way, you can test doGetClass in isolation from calling the database .
As often the case, inability to easily write tests for your functions is caused by a flaw in your application design. In this case the db_Class is tightly coupled to your BuilderClass.
A proper solution would be to have a Database object in your BuilderClass using dependency injection, and mocking that injection to return a static result.
class BuilderClass
{
protected $oDatabase;
public function __construct(db_Class $oDatabase) {
$this->oDatabase = $oDataabse;
}
public function getClass($someVars) {
$this->oDatabase->getDbRows($someVars);
}
}
This way, the Database object is easily replaced with a stub.
There are many ways to do this, but since we are talking PHP, you could leverage the magic class loader function.
Simply put, if you want to mock the data access layer, you just create an object with the actual name of the data class, and the autoloader is never called.
Want to actually access the database? don't define the class and the autoloader will be called when something tries to access the database, which should then know what to do to load the class.
Mostly my autoloaders, when I use them, tend to look something like this;
function __autoload($className)
{
if(file_exists('../includes/'.$className.'.php'))
require_once('../includes/'.$className.'.php');
}