I'm really sick of typing $this->database or $this->otherVarOrFunc every time I call something in my controller/model/wherever else. Is there some sort of OOP trick to have for example $database instead of $this->database in every function of my controller?
I have well defined structure of BaseController on MVC level and BaseObject for everything else class related. These two contains 5 to 20 object variables (depends on app size ) and I would be much more satisfied if typing $this-> wasnt required.
Does it have negative impact on overall performance? Thanks in advance
At the beginning of each class function, you could define a local variable for the function that references to the $this.For example:
class a {
function __construct() {
$this->aa = "hey";
}
public $aa;
public function aaa() {
$ab = &$this->aa;
$this->aa = "hey1";
echo $ab;
}
}
$b = new a;
$b->aaa();
Now throughout the function, use $ab instead of $this->aa
Related
I have Model_Group that extends ORM.
I have Controller_Group that gets a new ORM:
public function before()
{
global $orm_group;
$orm_group = ORM::factory('Group');
}
...and it has various methods that use it to get different subsets of data, such as...
public function action_get_by_type()
{
global $orm_group;
$type = $this->request->param('type');
$result = $orm_group->where('type', '=', $type)->find_all();
}
Then I have another controller (in a separate module) that I want to use to manipulate the object and call the relevant view. Let's call it Controller_Pages.
$orm_object = // Get the $result from Controller_Group somehow!
$this->template->content = View::factory( 'page1' )
->set('orm_object', $orm_object)
What is the best way to pass the ORM object from Controller_Group to Controller_Pages? Is this a good idea? If not, why not, and what better way is there of doing it?
The reason for separating them out into different controllers is because I want to be able to re-use the methods in Controller_Group from other modules. Each module may want to deal with the object in a different way.
This is the way I would do it, but first I would like to note that you shouldn't use global in this context.
If you want to set your ORM model in the before function, just make a variable in your controller and add it like this.
public function before()
{
$this->orm_group = ORM::factory('type');
}
In your Model your should also add the functions to access data and keep the controllers as small as possible. You ORM model could look something like this.
public class Model_Group extends ORM {
//All your other code
public function get_by_type($type)
{
return $this->where('type', '=', $type)->find_all();
}
}
Than in your controllers you can do something like this.
public function action_index()
{
$type = $this->request->param('type');
$result = $this->orm_group->get_by_type($type);
}
I hope this helps.
I always create an helper class for stuff like this
Class Grouphelper{
public static function getGroupByType($type){
return ORM::factory('Group')->where('type','=',$type)->find_all();
}
}
Now you're been able to get the groups by type where you want:
Grouphelper::getGroupByType($type);
As input I have a list of Books. As output I expect a SimilarBookCollection.
A SimilarBookCollection has an author, publishYear and list of Books. The SimilarBookCollection can't be created if the author of the books is different or if the publishYear is different.
The solution so far in PHP:
client.php
----
$arrBook = array(...); // array of books
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
$objSimilarBookCollection = new SimilarBookCollection($arrBook);
echo $objSimilarBookCollection->GetAuthor();
}
else {
echo 'Invalid input';
}
SimilarBookCollection.php
---
class SimilarBookCollection() {
public function SimilarBookCollection(array $arrBook) {
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
throw new Exception('Invalid books to create collection');
}
$this->author = $arrBook[0]->GetAuthor();
$this->publishYear = $arrBook[0]->GetPublishYear();
$this->books = $arrBook;
}
public function GetAuthor() {
return $this->author;
}
public function GetPublishYear() {
return $this->publishYear;
}
public function GetBooks() {
return $this->books;
}
}
SimilarBookCollectionValidator.php
---
class SimilarBookCollectionValidator() {
public function IsValid() {
$this->ValidateAtLeastOneBook();
$this->ValidateSameAuthor();
$this->ValidateSameYear();
return $this->blnValid;
}
... //actual validation routines
}
The goal is to have a "special" collection with only books that have the same author and publishYear. The idea is to easily access the repeating information like author or year from the object.
How would you name the SimilarBookCollection? The current name is to
generic. Using a name like SameYearAuthorBookCollection looks a bit
long and strange(if more conditions will be added then name will increase)
Would you use a Validator in SimilarBookCollection constructor using a
defensive programming style?
Would you change the design of the code? If yes how?
It all depends ;)
So if I were to aim for a generic adaptable solution I would do the following:
Validator in constructor
On one hand you are validating twice; that is informative in case of a broken precondition/contract (not giving a valid list), but is double the code to run - for what purpose exactly?
If you want to use this in a system depends on its size, how critical it is, product phase, and likely more criterias.
But then it also is controller logic fitted into a model meaning you are spreading your code around.
I would not put it in the constructor.
Name / Design
I would say keep the BookCollection generic as it is, and have any validation strictly in the controller space, instead of bloating the collection which essentially seems to be an array with the extra field of author.
If you want to differentiate between different collection types use either (multiple) inheritance or some sort of additional field "collectionType"; the former if you expect many derivatives or varying functionality to come (also keeps the logic where different nicely separated).
You could also consider your collection as a set on which you perform queries and for convenience's sake you could maintain some sort of meta data like $AuthorCount = N, $publicationDates = array(...) from which you can quickly derive the collection's nature. This approach would also keep your validator-code minimal (or non-existent), as it'd be implicitly in the collection and you could just do the validation in the controller keeping the effective logic behind it clearly visible.
That would also make it more comfortable for you in the future. But the question really is what you want and need it for, and what changes you expect, because you are supposed to fit your design to your requirements and likely changes.
For your very particular problem the constraints as I understand are as follows:
There is only one collection type class in the system at any given
point in time.
The class's items have several attributes, and for a particular, possibly changing subset of these (called identical attributes), the collection only accepts item lists where the chosen attributes of all items are identical.
The class provides getters for all identical attributes
The class must not be usable in any other way than the intended way.
If not for point 1 I would use a generic base class that is either parametrized (ie you tell it upon instantiation which is the set of identical attributes) or uses multiple inheritance (or in php traits) to compose arbitrary combinations with the needed interfaces. Children might rely on the base class but use a predefined subset of the identical attributes.
The parametrized variant might look something as follows:
class BookCollection {
public function __construct($book_list, $identical_fields=array())
{
if (empty($book_list))
{
throw new EmptyCollectionException("Empty book list");
}
$default = $book_list[0];
$this->ia = array();
foreach($identical_fields as $f)
{
$this->ia[$f] = $default->$f;
}
foreach($book_list as $book)
{
foreach($identical_fields as $f)
{
if ($this->ia[$f] !== $book->$f)
{
throw new NotIdenticalFieldException("Field $f is not identical for all");
}
}
}
$this->book_list = $book_list;
}
public function getIdentical($key)
{
$this->ia[$key];
}
}
final class BC_by_Author extends BookCollection{
public function __construct($book_list)
{
parent::__construct($book_list,array('author'));
}
public function getAuthor(){ $this->ia['author']; }
}
or fooling around with abstract and final types (not sure if it's valid like this)
abstract class BookCollection{
public final function __construct($book_list){...}
abstract public function getIdenticalAttributes();
}
final class BC_by_Author {
public function getIdenticalAttributes(){ return array('author'); }
public function getAuthor(){ return $this->ia['author']; }
}
If you rely on getters that do not necessarily match the field names I would go for multiple inheritance/traits.
The naming then would be something like BC_Field1Field2Field3.
Alternatively or additionally, you could also use exactly the same classname but develop your solutions in different namespaces, which would mean you wouldn't have to change your code when you change the namespace, plus you can keep it short in the controllers.
But because there will only ever be one class, I would name it BookCollection and not unnecessarily discuss it any further.
Because of constraint 4, the white box constraint, the given book list must be validated by the class itself, ie in the constructor.
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();
Providing that I have the following on:
TeamGamesDao Class:
public function listOfTeams() {
$select = $this->select()
->from(array('t'=>'teams'), array('cod_team','name','score'));
$rows = $this->fetchAll($select);
foreach($rows as &$row) {
$total = ????????????????????????????????
$done = $this->_getTeamsGamesDone($row['teamid']);
$row['percentage_of_games_done'] = $total > 0 ? ($done*100)/$total : 0);
}
return $rows;
}
private function _getTeamsGamesDone($teamid) {
/* ... */
}
And that, the ???????? is a value that will came from GamesDao Class by a public method there defined like: getTotalGames();
How should we call it on listOfTeams() ?
Should we instantiate it or call it statically, or some third possibility?
Thanks in advance,
MEM
One thing to be aware of here is that the call to getTotalGames() on the GameDao class occurs within the foreach($rows as &$row) loop. Assuming that the getTotalGames() method does its own db query, then you'd be hitting the db once within each iteration of the loop, which is generally frowned upon.
An alternative might be to rewrite the method to perform a join on the games and teams tables that includes a COUNT() and GROUP BY to get the per-team game counts.
Then you'd still be able to iterate through your teams, but it would only hit the db a single time.
In short, using static methods makes polymorphism impossible. As a result, it makes code harder to test (isolating dependencies) and less extensible in general. On the other hand, if the DAO instance was passed to the class as a dependency, then it would make testing easier and allow for swapping different implementations of the DAO at runtime.
Can a class return an object of itself.
In my example I have a class called "Change" which represents a change to the system, and I am wondering if it is in anyway against design principles to return an object of type Change or an ArrayList which is populated with all the recent Change objects.
Yes, a class can have a method that returns an instance of itself. This is quite a common scenario.
In C#, an example might be:
public class Change
{
public int ChangeID { get; set; }
private Change(int changeId)
{
ChangeID = changeId;
LoadFromDatabase();
}
private void LoadFromDatabase()
{
// TODO Perform Database load here.
}
public static Change GetChange(int changeId)
{
return new Change(changeId);
}
}
Yes it can. In fact, that's exactly what a singleton class does. The first time you call its class-level getInstance() method, it constructs an instance of itself and returns that. Then subsequent calls to getInstance() return the already-constructed instance.
Your particular case could use a similar method but you need some way of deciding the list of recent changes. As such it will need to maintain its own list of such changes. You could do this with a static array or list of the changes. Just be certain that the underlying information in the list doesn't disappear - this could happen in C++ (for example) if you maintained pointers to the objects and those objects were freed by your clients.
Less of an issue in an automatic garbage collection environment like Java since the object wouldn't disappear whilst there was still a reference to it.
However, you don't have to use this method. My preference with what you describe would be to have two clases, changelist and change. When you create an instance of the change class, pass a changelist object (null if you don't want it associated with a changelist) with the constructor and add the change to that list before returning it.
Alternatively, have a changelist method which creates a change itself and returns it, remembering the change for its own purposes.
Then you can query the changelist to get recent changes (however you define recent). That would be more flexible since it allows multiple lists.
You could even go overboard and allow a change to be associated with multiple changelists if so desired.
Another reason to return this is so that you can do function chaining:
class foo
{
private int x;
public foo()
{
this.x = 0;
}
public foo Add(int a)
{
this.x += a;
return this;
}
public foo Subtract(int a)
{
this.x -= a;
return this;
}
public int Value
{
get { return this.x; }
}
public static void Main()
{
foo f = new foo();
f.Add(10).Add(20).Subtract(1);
System.Console.WriteLine(f.Value);
}
}
$ ./foo.exe
29
There's a time and a place to do function chaining, and it's not "anytime and everywhere." But, LINQ is a good example of a place that hugely benefits from function chaining.
A class will often return an instance of itself from what is sometimes called a "factory" method. In Java or C++ (etc) this would usually be a public static method, e.g. you would call it directly on the class rather than on an instance of a class.
In your case, in Java, it might look something like this:
List<Change> changes = Change.getRecentChanges();
This assumes that the Change class itself knows how to track changes itself, rather than that job being the responsibility of some other object in the system.
A class can also return an instance of itself in the singleton pattern, where you want to ensure that only one instance of a class exists in the world:
Foo foo = Foo.getInstance();
The fluent interface methods work on the principal of returning an instance of itself, e.g.
StringBuilder sb = new StringBuilder("123");
sb.Append("456").Append("789");
You need to think about what you're trying to model. In your case, I would have a ChangeList class that contains one or more Change objects.
On the other hand, if you were modeling a hierarchical structure where a class can reference other instances of the class, then what you're doing makes sense. E.g. a tree node, which can contain other tree nodes.
Another common scenario is having the class implement a static method which returns an instance of it. That should be used when creating a new instance of the class.
I don't know of any design rule that says that's bad. So if in your model a single change can be composed of multiple changes go for it.