Method overloading in a model of Yii framework - php

I want to overload two methods in a model of Yii framework.
Here, I want to say that like in Java we have method overloading concept means method has same name but differs in number of parameters pass to that method. So these similar concept can apply in PHP Yii framework's model class.
In Yii model class, I want to create two methods like,
public function test(){
//method logic
}
public function test(int parameters){
//method logic
}
Is it possible to create like these? I am getting error like "cannot define same function".

What you are talking about is not supported in PHP. You could try using default values in function arguments. For eg.
function foo($int_param = 0) // do something
You could also use func_get_args. You define your function to not accept parameters and then get the arguments using func_get_args().
These approaches are suitable if there is not a lot of difference between the functions that you're trying to implement.

Related

Using a model inside a helper

I've a quick question related to the software architecure. In my application I have a model which contains a method to check the environment the application works in. Let's say the model is called "AppModel".
So, the AppModel::isDevEnv() indicates whether the app is runnig in production or development. It's easy to call this method inside others models, components etc.
The problem is when I want to check the environement inside a view. I created a helper with a propriety method inside just to cover the method from the model and return the result coming from exactly model's method.
class AppModel {
public function isDevEnv() {
return boolean;
}
}
class AppHelper {
public static function isDevEnv() {
$app = new AppModel();
return $app->isDevEnv();
}
}
Is it correct approach? Maybe it's a little bit overcomplicated? Maybe I should just make a static method inside a model and call it whenever I would like to call it?
If this is a legacy system I would recommend to refactor it to the desirable solution. If you want to have this helper or it is a required step for further refactoring then do it.
In general I would inject services which behave differently based on the environment instead of checking the environment inside your models. But it might not be easy with legacy system.

PHP: Passing Interface as Parameter

In .NET I have done that I passed Interfaces as parameters in class methods. I want to know is it possible in PHP?
My scnerio is that I have a class dealing with mqin system functionality. Now I want to integrate Notification system with it. I want to keep notification system separate since it is not the main part of the system plus I can use it somewhere else. If I have the following structure:
Interface INotification
{
public set()
public send()
}
And then I do:
class MyClass
{
public setNotifier(INotification $notifier)
{
}
}
So Is it possible that I can access set() and send() here after implementing them in a class? I want to know how this C# Example work that they set parameters of an Interface type.
Thanks
Yes, it is possible, pretty much as you wrote. Example of such interface: http://api.nette.org/2.0/source-Http.IResponse.php.html#18 and example of such parameter: http://api.nette.org/2.0/source-Http.Context.php.html#32
Yes, you can do as you coded. You can find more information and examples on php.net.
Note that specifying the type in the method parameter (type hinting) is allowed (PHP >= 5), but not required.

Can I declare the same multiple abstract methods with different parameters?

Can I somehow do this in an abstract class in php:
abstract function AddFilter();
abstract function AddFilter( /*array*/ $c_array='', /*string*/ $url='')
// ... etc...
using optional parameters / how do I do this?
if i just use the second one i get 'Declaration ofContent::AddFilter() must be compatible with that of ContentGeneric::AddFilter() '
update: ok... my method is now to add a single line callback function in the extended AddFilter() which works but is ofcourse not the nicest, whatever.
No, you can't do that. PHP does not support overloading functions with different signatures like e.g. C++ does. If you want to emulate something like this, take a look at the __call() magic method.

CodeIgniter: Where should a particular functionality go?

Here is a quick overview of the controllers functionality in most of the application:
controller loads a specific model, gets data from it, formats the data and passes the formatted data to the view.
Now there is a search page, which needs to do a search query over entire database (all models). It needs to show each type of data in its particular formatted output on a single page as a list.
The problem:
The search controller can do the search, dynamically load model for each record type, and get the data from model. Problem comes when the data needs to be formatted. I am trying to load the specific controller from the search controller, which is causing problems.
What to do?
PS: I tried using the 'Wick' library, but it fails when the controller's format function tries to use its own model and session object, giving errors about call to a member on a non-object.
After much refactoring and trial/error, It appears that the best way to achieve the above is this way:
Keep the format function in the base controller from which all other controllers are derived. The format options are passed to the function along with the data object as arguments.
Make a static function in each derived controller, which returns the formatting options of the data.
Inside the search controller (which is itself derived from the base controller), for each data object, call the static function of its particular controller which returns the data formatting options, then use that to format the object for the view.
I guess I can say I will stick to using the model only for interaction with the database, and let everything else be done by controller. If anyone has a better solution still, I am all ears.
It sounds like you want to use the Factory design pattern
Make this a library:
class MyModelFactory {
static public function Factory($data) {
$type = key($data);
return new $type($data);
}
}
now, in your controller, you can do something like this:
$model = MyModelFactory::Factory(array($_REQUEST['model'] => $_REQUEST));
and now you have an object of whatever model was specified in $_REQUEST['model']. Be sure to take any security precautions you may need for your application to assure the user has permissions to use the model that they request
Now, since you want to be using common methods and stuff, your models should probably be based off an abstract class / interface.. so instead of
class MyModelOne extends Model {
// stuff
}
You probably want something like this, to ensure your required methods will always be available:
abstract class MyAbstractModel extends Model {
protected $search_params;
public function __construct($data = array()) {
$search_params = $data['search_params'];
}
protected function GetSearchParameters() {
return $this->search_params;
}
abstract public function GetData();
abstract public function GetColumns();
abstract public function DefineViewOptions();
}
class MyModelOne extends MyAbstractModel {
public function GetData() {
$params = array();
$params[] = $this->db->escape_str($this->GetSearchParameters());
// return whatever data you want, given the search parameter(s)
}
public function GetColumns() {
// return some columns
}
public function DefineViewOptions() {
// return some configuration options
}
}
In general you can't load another controller from within a controller in CodeIgniter (although there are mods that allow you to do something like this).
I would try creating a class for formatting your data and add it to the application/library folder. Then load, use and re-use this class throughout your various controllers.
Here is a page from the CodeIgniter documentation Creating Your Own Libraries that explains the details and conventions.
Also, if a class is overkill, creating helper functions is an even lighter approach.
The difference between libraries and helpers in CodeIgniter is that libraries are classes, helpers are just a group of php functions.
Once you have formatted your data, you can load any view from any controller, so you should still have all the re-usability you need so you DRY (don't repeat yourself)
There are a few simple approaches based on the principle of what's simpler (versus what's perfectly DRY). Here's one alternative approach I use with CodeIgniter:
Instead of trying to load multiple controllers, reuse the view fragments from your search controller (or search route, depending which you're using). This requires using the same naming conventions for your data elements so the views are interchangeable, but you should be doing this anyway.
Instead of using multiple models for search, add a single Search model that knows about the things that can be searched on. If you want to prevent duplicate SQL, reuse the SQL between models (this can be done using constants, or loading SQL from disk).
Controllers are not great candidates for reuse from your own PHP code: they route actions and requests for resources to the things themselves. They are intended to be called via HTTP, using the URI interface you've come up with. Calling them from code is a coupling you want to avoid. That said, reusing controllers from JavaScript (or via cURL) is a great, decoupled way to reuse things in any web framework.

__call() function in CakePHP controllers?

is __call() function available in CakePHP's controllers? I used this function in Zend Framework.
class UsersController extends AppController {
function home(){
/*some action*/
}
function __call($m, $p){
print_r($m);
print_r($p);
}
}
I'm getting error like this:
Missing Method in UsersController
<?php
class UsersController extends AppController {
var $name = 'Users';
function somemethodsnotincontoller() {
}
}
?>
for the URL site.com/users/somemethodsnotincontoller
As many have pointed out here, __call() is a native PHP5 language "magic" method for catching calls to class methods that don't exist.
HOWEVER, Cake's core (I think it's the dispatcher) checks to see if the method exists first before calling it, and if it doesn't it renders the missing method error.
A solution might be for you to create your own AppError class, and handle the "catch all" method in there.
There is a limited amount of information in the cook book under Error handling
Yes but it won't work because CakePHP invokes actions through ReflectionMethod
// CakePHP 2.4.3
// Controller.php
public function invokeAction(CakeRequest $request) {
try {
$method = new ReflectionMethod($this, $request->params['action']);
and methods called this way are not processed by _call.
Used it for what?
The __call() method is a construct in PHP that you can use from within classes that allow you to "catch" calls to methods that don't exist in the class explicitly.
From PHP.net:
__call() is triggered when invoking inaccessible methods in an object
context.
So the answer is yes, as long as you are using PHP 5 or up.
__call() is a language construct so it is available in all versions of php that support it.
__call() is a magic-method of PHP, not any particular framework. It's impossible to answer this question without any context since __call() is defined in a particular object, not globally. Since CakePHP touts the fact that it is php4 compatible and __call() was introduced in php5 I would say no.
I looked at the production branch for Models and there is a call__() method, which looks like it tries to emulate PHP5's __call().
https://trac.cakephp.org/browser/branches/1.2.x.x/cake/libs/model/model.php?rev=4211#L437
Edit (Responding to comment):
Looking at Cake's base controller, there does not appear to be a 'catch-all' method available in controllers that mimics Zend's implementation of __call(). Your alternative to accomplish this would be to setup a route similar to cake's page route to catch all actions directed at a controller and send them to a single method.
Cake Trac for base controller:
https://trac.cakephp.org/browser/branches/1.2.x.x/cake/libs/controller/controller.php?rev=4211
Cake documentation on routing:
http://book.cakephp.org/view/46/Routes-Configuration
One of the examples in that documentation I referenced looks like something you can play with to accomplish what I mentioned above:
Router::connect(
'/cooks/:action/*', array('controller' => 'users', 'action' => 'index')
);
Regardless of the given-action, always use the index action.
In CakePHP 3, you definitely can use __call, just ensure that the controller defines isAction(). For example:
public function isAction($action) {
// To allow all actions to go to __call:
return TRUE;
}
public function __call($name, $arguments) {
//** your code called for every undefined action here **/
}
__call is one of PHP 5's magic methods (see "Method overloading" for more details).
If you are using PHP 5 (and you are, if you are usinf Zend Framework), you can have a __call method in your classes, not depending on the framework you are working with.

Categories