Managing collection of items through adding/removing - php

I want have an in-memory data structure to be able to add or remove an item (in this instance a student) into some sort of table (just like a shopping cart) from the collection class I have created. At the moment, it just displays students. For instance, if I click add student, it will pop up below, and I can delete this student from below also.
How I could implement this?
Here is my Member.php class
<?php
class Member {
private $name;
private $age;
private $gender;
private $course;
public function __construct($name,$age, $gender, $course){
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
$this->course = $course;
}
public function setName($name) { //Sets the age value
$this->name = $name;
}
public function setAge($age) { //Sets the age value
$this->age = $age;
}
public function setGender($gender) { //Sets the gender value
$this->gender = $gender;
}
public function setCourse ($course) {
$this->course = $course;
}
public function getName() { //Gets the name value
return $this->name;
}
public function getAge() { //Gets the age value
return $this->age;
}
public function getGender() { //Gets the gender value
return $this->gender;
}
public function getCourse() {
return $this->course;
}
}
?>
Here is my ObjectCollection.php
<?php
class ObjectCollection
{
//This is an array to hold line items
private $items_array ;
private $itemCounter; //Count the number of items
public function __construct() {
//Create an array object to hold line items
$this->items_array = array();
$this->itemCounter=0;
}
public function getItemCount(){
return $this->itemCounter;
}
public function addItem($item) {
$this->itemCounter++;
$this->items_array[] = $item;
}
public function getItem($index) {
return $this->items_array[$index];
}
}
?>
And finally displaying this through testcollection.php
<?php
$ObjColl = new ObjectCollection();
$member1 = new Member("Jessica Davidson", 21, "Female", "Computing");
$ObjColl->addItem($member1);
$member2 = new Member("Lucy Barnes", 22, "Female", "History");
$ObjColl->addItem($member2);
$member3 = new Member("Mark Smith", 24, "Male", "Social Science");
$ObjColl->addItem($member3);
for($i = 0;$i < $ObjColl->getItemCount();$i++){
$item = $ObjColl->getItem($i);
if ($item instanceof Member) {
print "<br> University Member: ";
}
print "Name: " . $item->getName();
print ". Age: " . $item->getAge();
print ". Gender: " . $item->getGender();
print ". Enrolled on: " .$item->getCourse() . " course<br>";
}
?>

At first if your ObjectCollection must collect only objects of Member class, use parameter type declaration. It’s good practice in OOP.
public function addItem(Member $item)
At second if you want work with ObjectCollection like with array, implement ArrayAccess and Iterator interfaces.
Example
<?php
class Member{
private $__name;
public function __construct($name){
$this->__name = $name;
}
public function getName(){
return $this->__name;
}
}
class MemberCollection implements ArrayAccess, Iterator{
private $__Collection = [];
private $__position = 0;
public function __construct(){
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->__Collection[] = $value;
} else {
$this->__Collection[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->__Collection[$offset]);
}
public function offsetUnset($offset) {
unset($this->__Collection[$offset]);
}
public function offsetGet($offset) {
return isset($this->__Collection[$offset]) ? $this->__Collection[$offset] : null;
}
function rewind() {
$this->__position = 0;
}
function current() {
return $this->__Collection[$this->__position];
}
function key() {
return $this->__position;
}
function next() {
++$this->__position;
}
function valid() {
return isset($this->__Collection[$this->__position]);
}
public function addItem(Member $Member){
$this->offsetSet(null, $Member);
}
}
$MC = new MemberCollection();
$Member1 = new Member('Name 1');
$Member2 = new Member('Name 2');
$MC->addItem($Member1);
$MC->addItem($Member2);
foreach ($MC as $Member){
echo '<br>' . $MC->key() . ':<br>';
var_dump($Member->getName());
}
unset($MC[0]); //Delete member from collection
?>

Related

convert object of class into string

class Person
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Business
{
protected $staff;
public function __construct(Staff $staff)
{
$this->staff = $staff;
}
public function hire(Person $person)
{
$this->staff->add($person);
}
public function getStaffMembers()
{
return $this->staff->members();
}
}
class Staff //staff é uma coleção, logo os membros são um array
{
protected $members = [];
public function __construct($members = [])
{
$this->members = $members;
}
public function add(Person $person)
{
$this->members[] = $person;
}
public function members()
{
return $this->members;
}
}
$daniel = new Person('Daniel Santos'); //name==$daniel santos
$staff = new Staff([$daniel]);
$laracasts = new Business($staff);
$laracasts->hire(new Person("Jorge"));
var_dump($laracasts->getStaffMembers());
I would like to print(implode("",$laracasts->getStaffMembers()); instead of just var_dump() it. Thanks.
Add a __toString "magic method" to your Person class.
class Person
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function __toString()
{
return $this->name;
}
}
__toString provides a string representation of the class, so you can use it in string contexts, like echo $person, or echo implode(', ', $laracasts->getStaffMembers());
In this example I just returned the person's name, but you can do more complex stuff in that method as well (formatting, etc.), as long as it returns a string.

Search in a container of objects with PHP

I have a container with some methods like add, get, and search, and within that class I have a variable that is an array holding instances of Car. How to make that object searchable by its name?
For example:
class Container {
private $cars = [];
public function __construct(array $cars = [])
{
$this->cars = $cars;
}
public function add($key, Car $car)
{
$this->cars[$key] = $car;
}
public function get($key)
{
return $this->cars[$key];
}
public function search($car)
{
// ...
}
};
class Car {
private $name;
public function __construct($name = null)
{
$this->name = $name;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
You'd need some sort of iterative search like a foreach() or array_filter().
For example:
public function search($car)
{
$matches = array();
foreach ($this->cars as $car) {
if ($car->getName() === $car) {
$matches[] = $car;
}
}
return $matches;
}
Or
public function search($car)
{
return array_filter($this->cars, function ($v) use ($car) {
return $v->getName() === $car;
});
}

Get containing object

I have two classes
class Table {
public $rows = array();
public $name;
public function __construct($name, $rows) {
$this->name = $name;
$this->rows = $rows;
}
}
class Row {
public $name;
public function __construct($name) {
$this->name = $name;
}
}
Now I want to create an object table and add 2 rows to it.
$rows = array(
new Row("Row 1"),
new Row("Row 2")
);
$table = new Table("Table 1", $rows);
So far so good..
But is there a possibility to get the containing table of a row?
For example:
foreach($table->rows AS $row) {
echo $row->name . ' is member of table ' . $row->getContainingTable()->name;
}
This is only an example...
You would have to change your Row class (pass the Table object to it):
class Row {
public $name;
protected $table;
public function __construct($name, Table $table) {
$this->name = $name;
$this->table = $table;
}
public function getContainingTable(){
return $this->table;
}
}
If you cannot do that on instantiation, create a setter method and use it after you pass the rows to the table :)
Actually, here's a better idea:
class Table {
public $rows = array();
public $name;
public function __construct($name, array $rows) {
$this->name = $name;
$this->rows = $rows;
foreach($rows as $row)
$row->setContainingTable($this);
}
}
class Row {
public $name;
protected $table;
public function __construct($name) {
$this->name = $name;
}
public function setContainingTable(Table $table){
$this->table = $table;
}
public function getContainingTable(){
return $this->table;
}
}
I think you should change your class structure to something like this
<?php
class MyCollection implements IteratorAggregate
{
private $items = array();
private $count = 0;
// Required definition of interface IteratorAggregate
public function getIterator() {
return new MyIterator($this->items);
}
public function add($value) {
$this->items[$this->count++] = $value;
}
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val) {
echo "key/value: [$key -> $val]\n\n";
}
?>
have a look at iterators in php 5 and see the examples this example is from there to

PHP aggregation of a property, of all objects in a class

apologies in advance for being a OO noob...
I am trying to write a method to aggregate a property of all objects that exist for a given class. The code below describes what I want to do.
Class TeamMember(){
function SetScore($value) {
$this->score = $value;
}
function GetTotalScoreForTeam() {
//best way to iterate over all the objects to get a sum??????
return totalScore;
}
}
$john = new TeamMember();
$john->SetScore('182');
$paul = new TeamMember();
$paul->SetScore('212');
$totalScore = TeamMember->GetTotalScoreForTeam;
Thanks!
Even if this is not the best way to approach this problem, I think it is the most explaining your problem with your pre-written code:
class TeamMember { // a class is not a function/method; removed the ()
public static $members = array(); // holds the instances
public $score; // It is simply good practice to declare your fields (it is not necessary)
function __construct () {
self::$members[] = $this; // save the instances accessible for your score-calcuating method
}
function setScore ($value) {
$this->score = $value;
}
static function getTotalScoreForTeam () { // a static method is best here
$totalScore = 0;
foreach (self::$members as $member) // foreach over the instances holding list
$totalScore += $member->score;
return $totalScore;
}
}
$john = new TeamMember();
$john->setScore('182');
$paul = new TeamMember();
$paul->setScore('212');
$totalScore = TeamMember::getTotalScoreForTeam(); // for static access, use a :: instead of ->
As Mike B said in the comment you should first group your TeamMember instances in an instance of a Team class and then run some aggregate function to calculate the total score of that particular team, e.g.
<?php
$team1 = Team::create('Team 1')
->add( TeamMember::create('john')->SetScore(182) )
->add( TeamMember::create('paul')->SetScore(212) );
$team2 = Team::create('Team 2')
->add( TeamMember::create('peter')->SetScore(200) )
->add( TeamMember::create('marry')->SetScore(300) );
foo($team1);
foo($team2);
function foo(Team $team) {
$score = $team->membersReduce(
function($v, $e) {
return $v+$e->getScore();
}
);
$members = $team->membersMap(
function($e) {
return $e->getName();
}
);
echo 'team : ', $team->getName(), "\r\n";
echo 'score: ', $score, "\r\n";
echo 'members: ', join(' | ', $members), "\r\n";
}
class TeamMember {
protected $score = 0;
protected $name;
public static function create($name) {
return new TeamMember($name);
}
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function SetScore($value) {
$this->score = $value;
return $this;
}
public function GetScore() {
return $this->score;
}
}
class Team {
protected $members = array();
protected $name;
public static function create($name) {
return new Team($name);
}
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function add(TeamMember $t) {
// <-- check if $t already member of team -->
$this->members[] = $t;
return $this;
}
public function membersReduce($fn) {
return array_reduce($this->members, $fn);
}
public function membersMap($fn) {
return array_map($fn, $this->members);
}
}
prints
team : Team 1
score: 394
members: john | paul
team : Team 2
score: 500
members: peter | marry

How perform USort() on an Array of Objects class definition as a method?

class Contact{
public $name;
public $bgcolor;
public $lgcolor;
public $email;
public $element;
public function __construct($name, $bgcolor, $lgcolor, $email, $element)
{
$this->name = $name;
$this->bgcolor = $bgcolor;
$this->lgcolor = $lgcolor;
$this->email = $email;
$this->element = $element;
}
public static function sortByName(Contact $p1, Contact $p2)
{
return strcmp($p1->name, $p2->name);
}
}
class ContactList implements Iterator, ArrayAccess
{
protected $_label;
protected $_contacts = array();
public function __construct($label)
{
$this->_label = $label;
}
public function getLabel()
{
return $this->_label;
}
public function addContact(Contact $contact)
{
$this->_contacts[] = $contact;
}
public function current()
{
return current($this->_contacts);
}
public function key()
{
return key($this->_contacts);
}
public function next()
{
return next($this->_contacts);
}
public function rewind()
{
return reset($this->_contacts);
}
public function valid()
{
return current($this->_contacts);
}
public function offsetGet($offset)
{
return $this->_contacts[$offset];
}
public function offsetSet($offset, $data)
{
if (!$data instanceof Contact)
throw new InvalidArgumentException('Only Contact objects allowed in a ContactList');
if ($offset == '')
{
$this->_contacts[] = $data;
} else
{
$this->_contacts[$offset] = $data;
}
}
public function offsetUnset($offset)
{
unset($this->_contacts[$offset]);
}
public function offsetExists($offset) {
return isset($this->_contacts[$offset]);
}
public function sort($attribute = 'name')
{
$sortFct = 'sortBy' . ucfirst(strtolower($attribute));
if (!in_array($sortFct, get_class_methods('Contact')))
{
throw new Exception('contact->sort(): Can\'t sort by ' . $attribute);
}
usort($this->contact, 'ContactList::' . $sortFct);
}
}
public function Sort($property, $asc=true)
{
// this is where sorting logic takes place
$_pd = $this->_contact->getProperty($property);
if ($_pd == null)
{
user_error('Property '.$property.' does not exist in class '.$this->_contact->getName(), E_WARNING);
return;
}
// set sortDescriptor
ContactList::$sortProperty = $_pd;
// and apply sorting
usort($this->_array, array('ContactList', ($asc?'USortAsc':'USortDesc')));
}
function getItems(){
return $this->_array;
}
class SortableItem extends ContactList
{
static public $sortProperty;
static function USortAsc($a, $b)
{
/*#var $_pd ReflectionProperty*/
/*
$_pd = self::$sortProperty;
if ($_pd !== null)
{
if ($_pd->getValue($a) === $_pd->getValue($b))
return 0;
else
return (($_pd->getValue($a) < $_pd->getValue($b))?-1:1);
}
return 0;
}
static function USortDesc($a, $b)
{
return -(self::USortAsc($a,$b));
}
}
This approach keeps giving me PHP Warnings: usort() [function.usort]: of all kinds which I can provide later as needed to comment out those methods and definitions in order to test and fix some minor bugs of our program.
**$billy parameters are already defined.
$all -> addContact($billy);
// --> ended up adding each contact manually above
$all->Sort('name',true);
$items = $all->getItems();
foreach($items as $contact)
{
echo $contact->__toString();
}
$all->sort();
The reason for using usort is to re-arrange the order alphabetically by name but somehow is either stating that the function comparison needs to be an array or another errors which obviously I have seemed to pass. Any help would be greatly appreciated, thanks in advance.
It's happening because the variable inside the usort call is not a valid array. You use $this->_contacts everywhere, but your usort line is:
usort($this->contact, 'ContactList::' . $sortFct);
Try changing that to:
usort($this->_contacts, 'ContactList::' . $sortFct);
<?php
class Contact{
public $name;
public $bgcolor;
public $lgcolor;
public $email;
public $element;
public function __construct($name, $bgcolor, $lgcolor, $email, $element)
{
$this->name = $name;
$this->bgcolor = $bgcolor;
$this->lgcolor = $lgcolor;
$this->email = $email;
$this->element = $element;
}
}
class ContactList implements Iterator, ArrayAccess
{
public $_label;
public $_contacts = array();
public function __construct($label)
{
$this->_label = $label;
}
public function getLabel()
{
return $this->_label;
}
public function addContact(Contact $contact)
{
$this->_contacts[] = $contact;
}
public function current()
{
return current($this->_contacts);
}
public function key()
{
return key($this->_contacts);
}
public function next()
{
return next($this->_contacts);
}
public function rewind()
{
return reset($this->_contacts);
}
public function valid()
{
return current($this->_contacts);
}
public function offsetGet($offset)
{
return $this->_contacts[$offset];
}
public function offsetSet($offset, $data)
{
if (!$data instanceof Contact)
throw new InvalidArgumentException('Only Contact objects allowed in a ContactList');
if ($offset == '')
{
$this->_contacts[] = $data;
} else
{
$this->_contacts[$offset] = $data;
}
}
public function offsetUnset($offset)
{
unset($this->_contacts[$offset]);
}
public function offsetExists($offset) {
return isset($this->_contacts[$offset]);
}
/* This is the comparing function to be used with usort to make it alphabetically ordered for All Contacts */
public function sort_by($field, &$arr, $sorting='SORT_DSC', $case_insensitive=true){
if(is_array($arr) && (count($arr)>0) && ( ( is_array($arr[0]) && isset($arr[0][$field]) ) || ( is_object($arr[0]) && isset($arr[0]->$field) ) ) ){
if($case_insensitive==true) $strcmp_fn = "strnatcasecmp";
else $strcmp_fn = "strnatcmp";
if($sorting=='SORT_DSC'){
$fn = create_function('$a,$b', '
if(is_object($a) && is_object($b)){
return '.$strcmp_fn.'($a->'.$field.', $b->'.$field.');
}else if(is_array($a) && is_array($b)){
return '.$strcmp_fn.'($a["'.$field.'"], $b["'.$field.'"]);
}else return 0;
');
}else if($sorting=='SORT_ASC'){
$fn = create_function('$a,$b', '
if(is_object($a) && is_object($b)){
return '.$strcmp_fn.'($b->'.$field.', $a->'.$field.');
}else if(is_array($a) && is_array($b)){
return '.$strcmp_fn.'($b["'.$field.'"], $a["'.$field.'"]);
}else return 0;
');
}
usort($arr, $fn);
return true;
}else{
return false;
}
}
}
?
The call:
$all->sort_by('name',$all->_contacts,'SORT_DSC','false');

Categories