I came up with a solution (in PHP) to a problem and am wondering if it is a named Design Pattern, and if it is good practice.
I have a collection class and an item class. The collection class is the only one allowed to set the item class's protected data, besides the class itself.
I did that by giving the item
class a method that takes the collection
object as an argument. The item
object then sets its data with the collection
objects.
That way, we can say:
$item_coll = new collection();
$item_coll->load($criterion1, $criterion2);
Because the collection implements IteratorAggregate, we can also do this:
foreach($item_coll as $item) {
echo 'Item name is ' . $item->getName();
}
Even after a collection is loaded, you can get a sub collection using the getBy($property,$value)
method:
$sub_collection = $item_coll->getBy('color','green'); // new collection object with green items
And now I have a collection of item
objects with all their data set.
Here are the classes (with impertinent methods/properties not shown).
class item {
protected $id; // id from database table
protected $prop1; // properties also from database
protected $prop2;
public function setData(collection $coll, $id) {
$data = $coll->getData($id);
foreach($data as $key=>$value) {
$this->$key = $value
}
return $this;
}
public function getId() {
return $this->id;
}
}
class collection implements IteratorAggregate { // interface for foreach access to $collection
protected $data = array();
protected $collection = array(); // contains `item` objects
public function getData($id) {
if(array_key_exists($id,$this->data) ) {
return $this->data[$id];
} else return array();
}
public function load(someClass $obj1, someClass2 $obj2) { // arguments not relevant here, they determine the contents of the collection
// based on arguments, data is loaded from database into $this->data;
foreach($rows as $row) { // database data
$this->data[$id] = $row;
$obj = $this->collection[$id] = new item();
$obj->setData($this,$id); // collection object passes itself into item object
}
}
public function html() {//
foreach($this as $obj) {
// loop through collection to create an html table for display
}
}
public function addItem(item $item) { // add already-existing items to collection
if(!array_key_exists($id,$this->collection) ) {
$this->collection[$item->getId()] = $item;
}
}
public function getIterator() { // for IteratorAggregate interface
return new ArrayIterator($this->collection);
}
public function getBy($property,$value) {
$collection = new static(); // new collection created
// loop through $this object and fill $collection with matching item objects
return $collection;
}
public function getById($id) { // get a single item object by its id
if(array_key_exists($id,$this->collection) ) {
return $this->collection[$id];
}
}
}
collection
to be able to call thesetData()
method ofitem
? My purpose was to limit it to the collection class, but it's possible that in the future I might want to allow another class. So do you think this is a bad idea? Should I not worry about who is setting the object's data, and perhaps have the object validate whatever data is being set? Or have some kind of validator class? My purpose was to establish a trusted "partner class" of sorts. – Buttle Butkus Feb 25 '15 at 8:23$id
visible to the "outside"? – Stefan Hanke Feb 25 '15 at 18:49get($property)
method in a lot of classes but recently have been starting to change over to writing specific methods likegetId()
to limit access. Currently,$id
is visible through those methods. – Buttle Butkus Feb 25 '15 at 19:53