Laravel replace property with another if it is 0 - php

I have two columns, price and offer_price.
When I call $products->price, I would like it to bring back the offer_price if it is above 0, if not, return the price.
My modal:
class Product extends Eloquent {
protected $table = 'products';
public function type() {
return $this->hasOne('ProductTypes', 'id', 'type_id');
}
public function brand()
{
return $this->hasOne('ProductBrands', 'id', 'brand_id');
}
public function image() {
return $this->hasMany('ProductImages');
}
public function toArray() {
$ar = $this->attributes;
$ar['type'] = $this->type;
$ar['brand'] = $this->spec_brand;
$ar['price'] = $this->price;
return $ar;
}
public function getSpecBrandAttribute() {
$brand = $this->brand()->first();
return (isset($brand->brand) ? $brand->brand : '');
}
public function getPriceAttribute() {
$price = $this->price;
return (isset($price->price) ? $price->price : '');
}
}
I'm trying to use it here:
$brands = array();
$prices = array();
$out = '';
foreach ($products as $product) {
$brands[$product->brand->id] = $product->brand->brand;
$prices[] = $product->price;
}

You're on the right track. You can find your data in the $attributes array member of your model, rather than distinct member variables in your model.
How about:
public function getPriceAttribute()
{
$which = (0 < $this->attributes['offer_price'] ? 'offer_price' : 'price');
return $this->attributes[$which];
}
Though I would recommend a name other than 'price', unless you completely want to mask 'price' from the usual Laravel interaction. Perhaps $modal->best_price?

Related

how to call a function inside function on PHP OOP [duplicate]

I am using PHP 5 and I've heard of a new featured in the object-oriented approach, called 'method chaining'. What is it exactly? How do I implement it?
It's rather simple, really. You have a series of mutator methods that all return the original (or other) object. That way, you can keep calling methods on the returned object.
<?php
class fakeString
{
private $str;
function __construct()
{
$this->str = "";
}
function addA()
{
$this->str .= "a";
return $this;
}
function addB()
{
$this->str .= "b";
return $this;
}
function getStr()
{
return $this->str;
}
}
$a = new fakeString();
echo $a->addA()->addB()->getStr();
This outputs "ab"
Try it online!
Basically, you take an object:
$obj = new ObjectWithChainableMethods();
Call a method that effectively does a return $this; at the end:
$obj->doSomething();
Since it returns the same object, or rather, a reference to the same object, you can continue calling methods of the same class off the return value, like so:
$obj->doSomething()->doSomethingElse();
That's it, really. Two important things:
As you note, it's PHP 5 only. It won't work properly in PHP 4 because it returns objects by value and that means you're calling methods on different copies of an object, which would break your code.
Again, you need to return the object in your chainable methods:
public function doSomething() {
// Do stuff
return $this;
}
public function doSomethingElse() {
// Do more stuff
return $this;
}
Try this code:
<?php
class DBManager
{
private $selectables = array();
private $table;
private $whereClause;
private $limit;
public function select() {
$this->selectables = func_get_args();
return $this;
}
public function from($table) {
$this->table = $table;
return $this;
}
public function where($where) {
$this->whereClause = $where;
return $this;
}
public function limit($limit) {
$this->limit = $limit;
return $this;
}
public function result() {
$query[] = "SELECT";
// if the selectables array is empty, select all
if (empty($this->selectables)) {
$query[] = "*";
}
// else select according to selectables
else {
$query[] = join(', ', $this->selectables);
}
$query[] = "FROM";
$query[] = $this->table;
if (!empty($this->whereClause)) {
$query[] = "WHERE";
$query[] = $this->whereClause;
}
if (!empty($this->limit)) {
$query[] = "LIMIT";
$query[] = $this->limit;
}
return join(' ', $query);
}
}
// Now to use the class and see how METHOD CHAINING works
// let us instantiate the class DBManager
$testOne = new DBManager();
$testOne->select()->from('users');
echo $testOne->result();
// OR
echo $testOne->select()->from('users')->result();
// both displays: 'SELECT * FROM users'
$testTwo = new DBManager();
$testTwo->select()->from('posts')->where('id > 200')->limit(10);
echo $testTwo->result();
// this displays: 'SELECT * FROM posts WHERE id > 200 LIMIT 10'
$testThree = new DBManager();
$testThree->select(
'firstname',
'email',
'country',
'city'
)->from('users')->where('id = 2399');
echo $testThree->result();
// this will display:
// 'SELECT firstname, email, country, city FROM users WHERE id = 2399'
?>
Another Way for static method chaining :
class Maker
{
private static $result = null;
private static $delimiter = '.';
private static $data = [];
public static function words($words)
{
if( !empty($words) && count($words) )
{
foreach ($words as $w)
{
self::$data[] = $w;
}
}
return new static;
}
public static function concate($delimiter)
{
self::$delimiter = $delimiter;
foreach (self::$data as $d)
{
self::$result .= $d.$delimiter;
}
return new static;
}
public static function get()
{
return rtrim(self::$result, self::$delimiter);
}
}
Calling
echo Maker::words(['foo', 'bob', 'bar'])->concate('-')->get();
echo "<br />";
echo Maker::words(['foo', 'bob', 'bar'])->concate('>')->get();
Method chaining means that you can chain method calls:
$object->method1()->method2()->method3()
This means that method1() needs to return an object, and method2() is given the result of method1(). Method2() then passes the return value to method3().
Good article: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html
There are 49 lines of code which allows you to chain methods over arrays like this:
$fruits = new Arr(array("lemon", "orange", "banana", "apple"));
$fruits->change_key_case(CASE_UPPER)->filter()->walk(function($value,$key) {
echo $key.': '.$value."\r\n";
});
See this article which shows you how to chain all the PHP's seventy array_ functions.
http://domexception.blogspot.fi/2013/08/php-magic-methods-and-arrayobject.html
A fluent interface allows you to chain method calls, which results in less typed characters when applying multiple operations on the same object.
class Bill {
public $dinner = 20;
public $desserts = 5;
public $bill;
public function dinner( $person ) {
$this->bill += $this->dinner * $person;
return $this;
}
public function dessert( $person ) {
$this->bill += $this->desserts * $person;
return $this;
}
}
$bill = new Bill();
echo $bill->dinner( 2 )->dessert( 3 )->bill;
I think this is the most relevant answer.
<?php
class Calculator
{
protected $result = 0;
public function sum($num)
{
$this->result += $num;
return $this;
}
public function sub($num)
{
$this->result -= $num;
return $this;
}
public function result()
{
return $this->result;
}
}
$calculator = new Calculator;
echo $calculator->sum(10)->sub(5)->sum(3)->result(); // 8
If you mean method chaining like in JavaScript (or some people keep in mind jQuery), why not just take a library that brings that dev. experience in PHP? For example Extras - https://dsheiko.github.io/extras/ This one extends PHP types with JavaScript and Underscore methods and provides chaining:
You can chain a particular type:
<?php
use \Dsheiko\Extras\Arrays;
// Chain of calls
$res = Arrays::chain([1, 2, 3])
->map(function($num){ return $num + 1; })
->filter(function($num){ return $num > 1; })
->reduce(function($carry, $num){ return $carry + $num; }, 0)
->value();
or
<?php
use \Dsheiko\Extras\Strings;
$res = Strings::from( " 12345 " )
->replace("/1/", "5")
->replace("/2/", "5")
->trim()
->substr(1, 3)
->get();
echo $res; // "534"
Alternatively you can go polymorphic:
<?php
use \Dsheiko\Extras\Any;
$res = Any::chain(new \ArrayObject([1,2,3]))
->toArray() // value is [1,2,3]
->map(function($num){ return [ "num" => $num ]; })
// value is [[ "num" => 1, ..]]
->reduce(function($carry, $arr){
$carry .= $arr["num"];
return $carry;
}, "") // value is "123"
->replace("/2/", "") // value is "13"
->then(function($value){
if (empty($value)) {
throw new \Exception("Empty value");
}
return $value;
})
->value();
echo $res; // "13"
Below is my model that is able to find by ID in the database. The with($data) method is my additional parameters for relationship so I return the $this which is the object itself. On my controller I am able to chain it.
class JobModel implements JobInterface{
protected $job;
public function __construct(Model $job){
$this->job = $job;
}
public function find($id){
return $this->job->find($id);
}
public function with($data=[]){
$this->job = $this->job->with($params);
return $this;
}
}
class JobController{
protected $job;
public function __construct(JobModel $job){
$this->job = $job;
}
public function index(){
// chaining must be in order
$this->job->with(['data'])->find(1);
}
}

Laravel Submodel Of an Model

In my Laravel application, I need submodels of the base ORM model, for specific types of item in my DB which is specified in 'type' column in database.
In my base model, I use this override for function newFromBuilder
// OVERRIDES
public function newFromBuilder($attributes = [], $connection = null)
{
$class = "\\App\\Models\\" . ucfirst($attributes->type);
if (class_exists($class)) {
$model = new $class();
} else {
$model = $this->newInstance([], true);
}
$model->setRawAttributes((array)$attributes, true);
$model->setConnection($connection ?: $this->getConnectionName());
$model->fireModelEvent('retrieved', false);
return $model;
}
but for some reason when i call save or update function in submodel nothing happen :( Each submodel should ingered save function of fase model s that right ? Could anybody help me to fix issue with save function ?
Base model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Carbon;
use App\Models\Devices;
use App\Models\Records;
use App\Models\Rooms;
use App\Helpers\SettingManager;
use App\Types\GraphPeriod;
use App\Types\PropertyType;
class Properties extends Model
{
protected $fillable = [];
protected $table = 'sh_properties';
protected $primaryKey = 'id';
public $period = GraphPeriod::DAY;
//OVERIDES
public function newFromBuilder($attributes = [], $connection = null)
{
$class = "\\App\\Models\\" . ucfirst($attributes->type);
if (class_exists($class)) {
$model = new $class();
} else {
$model = $this->newInstance([], true);
}
$model->setRawAttributes((array)$attributes, true);
$model->setConnection($connection ?: $this->getConnectionName());
$model->fireModelEvent('retrieved', false);
return $model;
}
//NEW RELATIONS
public function records()
{
return $this->hasMany(Records::class, 'property_id');
}
public function latestRecord()
{
return $this->hasOne(Records::class, 'property_id')->latestOfMany();
}
public function device()
{
return $this->belongsTo(Devices::class);
}
public function room()
{
return $this->belongsTo(Rooms::class);
}
public function settings()
{
if ($settings = SettingManager::getGroup('property-' . $this->id)) {
return $settings;
}
return false;
}
//FUNCTIONS
public function getLatestRecordNotNull()
{
return Records::where("property_id", $this->id)->where("value", "!=", null)->where("value", "!=", 0)->first();
}
//Virtual Values
use HasFactory;
//Add Function for mutator for vaue (vith units) and rav value
public function values()
{
$dateFrom = Carbon::now()->subDays(1);
switch ($this->period) {
case GraphPeriod::WEEK:
$dateFrom = Carbon::now()->subWeek(1);
break;
case GraphPeriod::MONTH:
$dateFrom = Carbon::now()->subMonth(1);
break;
case GraphPeriod::YEAR:
$dateFrom = Carbon::now()->subYear(1);
break;
}
return $this->hasMany(Records::class, 'property_id')->whereDate('created_at', '>', $dateFrom)->orderBy('created_at', 'DESC');
}
public function getAgregatedValuesAttribute($period = GraphPeriod::DAY)
{
$dateFrom = Carbon::now()->subDays(1);
$periodFormat = "%Y-%m-%d %hh";
switch ($this->period) {
case GraphPeriod::WEEK:
$dateFrom = Carbon::now()->subWeek(1);
$periodFormat = "%Y-%m-%d";
break;
case GraphPeriod::MONTH:
$dateFrom = Carbon::now()->subMonth(1);
$periodFormat = "%Y-%m-%d";
break;
case GraphPeriod::YEAR:
$dateFrom = Carbon::now()->subYear(1);
$periodFormat = "%Y-%m";
break;
}
$agregatedData = Records::select(['value', 'done', 'created_at'])
->selectRaw("DATE_FORMAT(created_at, ?) as period", [$periodFormat])
->selectRaw("ROUND(MIN(value), 1) AS min")
->selectRaw("ROUND(MAX(value), 1) AS max")
->selectRaw("ROUND(AVG(value), 1) AS value")
->where('property_id', $this->id)
->orderBy('created_at', 'DESC')
->groupBy('period');
$agregatedData->where('created_at', '>=', $dateFrom);
return $agregatedData->get();
}
public function last_value()
{
return $this->hasOne(Records::class, 'property_id', 'id')->latest();
}
//Virtual Values
//Virtual Values
/**
* Minimum value that property had in past.
*
* #return int
*/
public function getMaxValueAttribute()
{
if ($this->records) {
return $this->records->max("value");
}
return false;
}
/**
* Maximum value that property had in past.
*
* #return int
*/
public function getMinValueAttribute()
{
if ($this->records) {
return $this->records->min("value");
}
return false;
}
/**
* step value used to increment each value usually used for range type or thermostats, graphs also.
*
* #return int
*/
public function getStepValueAttribute()
{
if ($step = SettingManager::get('step', 'property-' . $this->id)) {
return ($step->value < 1 ? $step->value : 1);
}
return false;
}
/**
* max set value for prop
*
* #return int
*/
public function getMaxValueSettingAttribute()
{
if ($step = SettingManager::get('max', 'property-' . $this->id)) {
return ($step->value > 1 ? $step->value : 1);
}
return false;
}
/**
* min set value for prop
*
* #return int
*/
public function getMinValueSettingAttribute()
{
if ($step = SettingManager::get('min', 'property-' . $this->id)) {
return ($step->value > 1 ? $step->value : 1);
}
return false;
}
public function setValue($value)
{
$record = new Records;
$record->value = $value;
$record->property_id = $this->id;
$record->save();
return true;
}
}
Submodel
namespace App\Models;
use App\Models\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Humi extends Properties
{
protected $historyDefault = 90;
protected $unitsDefault = "%";
protected $iconDefault = "";
public function save(array $options = [])
{
// before save code
$result = parent::save($options); // returns boolean
// after save code
return $result; // do not ignore it eloquent calculates this value and returns this, not just to ignore
}
}
Thank you in advance for any suggestions or help :)
When a new instance is created with the $this->newInstance() function, the $model->exists property is set to true. I think you should do the same in your if statement as well. Otherwise it will try to create a new record in the database.
It might be a good idea to copy the rest of the function as well to avoid any other problems it may cause.
if (class_exists($class)) {
$model = new $class();
// Important
$model->exists = true;
$model->setTable($this->getTable());
$model->mergeCasts($this->casts);
} else {
$model = $this->newInstance([], true);
}

PHP How does it works? Function()->Function() [duplicate]

I am using PHP 5 and I've heard of a new featured in the object-oriented approach, called 'method chaining'. What is it exactly? How do I implement it?
It's rather simple, really. You have a series of mutator methods that all return the original (or other) object. That way, you can keep calling methods on the returned object.
<?php
class fakeString
{
private $str;
function __construct()
{
$this->str = "";
}
function addA()
{
$this->str .= "a";
return $this;
}
function addB()
{
$this->str .= "b";
return $this;
}
function getStr()
{
return $this->str;
}
}
$a = new fakeString();
echo $a->addA()->addB()->getStr();
This outputs "ab"
Try it online!
Basically, you take an object:
$obj = new ObjectWithChainableMethods();
Call a method that effectively does a return $this; at the end:
$obj->doSomething();
Since it returns the same object, or rather, a reference to the same object, you can continue calling methods of the same class off the return value, like so:
$obj->doSomething()->doSomethingElse();
That's it, really. Two important things:
As you note, it's PHP 5 only. It won't work properly in PHP 4 because it returns objects by value and that means you're calling methods on different copies of an object, which would break your code.
Again, you need to return the object in your chainable methods:
public function doSomething() {
// Do stuff
return $this;
}
public function doSomethingElse() {
// Do more stuff
return $this;
}
Try this code:
<?php
class DBManager
{
private $selectables = array();
private $table;
private $whereClause;
private $limit;
public function select() {
$this->selectables = func_get_args();
return $this;
}
public function from($table) {
$this->table = $table;
return $this;
}
public function where($where) {
$this->whereClause = $where;
return $this;
}
public function limit($limit) {
$this->limit = $limit;
return $this;
}
public function result() {
$query[] = "SELECT";
// if the selectables array is empty, select all
if (empty($this->selectables)) {
$query[] = "*";
}
// else select according to selectables
else {
$query[] = join(', ', $this->selectables);
}
$query[] = "FROM";
$query[] = $this->table;
if (!empty($this->whereClause)) {
$query[] = "WHERE";
$query[] = $this->whereClause;
}
if (!empty($this->limit)) {
$query[] = "LIMIT";
$query[] = $this->limit;
}
return join(' ', $query);
}
}
// Now to use the class and see how METHOD CHAINING works
// let us instantiate the class DBManager
$testOne = new DBManager();
$testOne->select()->from('users');
echo $testOne->result();
// OR
echo $testOne->select()->from('users')->result();
// both displays: 'SELECT * FROM users'
$testTwo = new DBManager();
$testTwo->select()->from('posts')->where('id > 200')->limit(10);
echo $testTwo->result();
// this displays: 'SELECT * FROM posts WHERE id > 200 LIMIT 10'
$testThree = new DBManager();
$testThree->select(
'firstname',
'email',
'country',
'city'
)->from('users')->where('id = 2399');
echo $testThree->result();
// this will display:
// 'SELECT firstname, email, country, city FROM users WHERE id = 2399'
?>
Another Way for static method chaining :
class Maker
{
private static $result = null;
private static $delimiter = '.';
private static $data = [];
public static function words($words)
{
if( !empty($words) && count($words) )
{
foreach ($words as $w)
{
self::$data[] = $w;
}
}
return new static;
}
public static function concate($delimiter)
{
self::$delimiter = $delimiter;
foreach (self::$data as $d)
{
self::$result .= $d.$delimiter;
}
return new static;
}
public static function get()
{
return rtrim(self::$result, self::$delimiter);
}
}
Calling
echo Maker::words(['foo', 'bob', 'bar'])->concate('-')->get();
echo "<br />";
echo Maker::words(['foo', 'bob', 'bar'])->concate('>')->get();
Method chaining means that you can chain method calls:
$object->method1()->method2()->method3()
This means that method1() needs to return an object, and method2() is given the result of method1(). Method2() then passes the return value to method3().
Good article: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html
There are 49 lines of code which allows you to chain methods over arrays like this:
$fruits = new Arr(array("lemon", "orange", "banana", "apple"));
$fruits->change_key_case(CASE_UPPER)->filter()->walk(function($value,$key) {
echo $key.': '.$value."\r\n";
});
See this article which shows you how to chain all the PHP's seventy array_ functions.
http://domexception.blogspot.fi/2013/08/php-magic-methods-and-arrayobject.html
A fluent interface allows you to chain method calls, which results in less typed characters when applying multiple operations on the same object.
class Bill {
public $dinner = 20;
public $desserts = 5;
public $bill;
public function dinner( $person ) {
$this->bill += $this->dinner * $person;
return $this;
}
public function dessert( $person ) {
$this->bill += $this->desserts * $person;
return $this;
}
}
$bill = new Bill();
echo $bill->dinner( 2 )->dessert( 3 )->bill;
I think this is the most relevant answer.
<?php
class Calculator
{
protected $result = 0;
public function sum($num)
{
$this->result += $num;
return $this;
}
public function sub($num)
{
$this->result -= $num;
return $this;
}
public function result()
{
return $this->result;
}
}
$calculator = new Calculator;
echo $calculator->sum(10)->sub(5)->sum(3)->result(); // 8
If you mean method chaining like in JavaScript (or some people keep in mind jQuery), why not just take a library that brings that dev. experience in PHP? For example Extras - https://dsheiko.github.io/extras/ This one extends PHP types with JavaScript and Underscore methods and provides chaining:
You can chain a particular type:
<?php
use \Dsheiko\Extras\Arrays;
// Chain of calls
$res = Arrays::chain([1, 2, 3])
->map(function($num){ return $num + 1; })
->filter(function($num){ return $num > 1; })
->reduce(function($carry, $num){ return $carry + $num; }, 0)
->value();
or
<?php
use \Dsheiko\Extras\Strings;
$res = Strings::from( " 12345 " )
->replace("/1/", "5")
->replace("/2/", "5")
->trim()
->substr(1, 3)
->get();
echo $res; // "534"
Alternatively you can go polymorphic:
<?php
use \Dsheiko\Extras\Any;
$res = Any::chain(new \ArrayObject([1,2,3]))
->toArray() // value is [1,2,3]
->map(function($num){ return [ "num" => $num ]; })
// value is [[ "num" => 1, ..]]
->reduce(function($carry, $arr){
$carry .= $arr["num"];
return $carry;
}, "") // value is "123"
->replace("/2/", "") // value is "13"
->then(function($value){
if (empty($value)) {
throw new \Exception("Empty value");
}
return $value;
})
->value();
echo $res; // "13"
Below is my model that is able to find by ID in the database. The with($data) method is my additional parameters for relationship so I return the $this which is the object itself. On my controller I am able to chain it.
class JobModel implements JobInterface{
protected $job;
public function __construct(Model $job){
$this->job = $job;
}
public function find($id){
return $this->job->find($id);
}
public function with($data=[]){
$this->job = $this->job->with($params);
return $this;
}
}
class JobController{
protected $job;
public function __construct(JobModel $job){
$this->job = $job;
}
public function index(){
// chaining must be in order
$this->job->with(['data'])->find(1);
}
}

Magento 2 : How to get product attributes collection in custom module block file whose status is visible =>yes?

Here is my function for calling product attribute collection I have already get product attributes for the product's which are enabled but I am having issue in filtering them according to their own visibility i.e I want only those product attributes collection whose status is set visible from admin....
class ProductList extends \Magento\Framework\View\Element\Template
{
protected $_attributeFactory;
public function __construct(
\Magento\Catalog\Model\ResourceModel\Eav\Attribute $attributeFactory
){
parent::__construct($context);
$this->_attributeFactory = $attributeFactory;
}
public function getallattributes()
{
$arr = [];
$attributeInfo = $this->_attributeFactory->getCollection()->addFieldToFilter(\Magento\Eav\Model\Entity\Attribute\Set::KEY_ENTITY_TYPE_ID, 4);
foreach($attributeInfo as $attributes)
{
$attributeId = $attributes->getAttributeId();
// You can get all fields of attribute here
$arr[$attributes->getAttributeId()] = $attributes->getFrontendLabel();
}
return $arr;
} }
No tested but it will do job for you
$attributeInfo = $this->_attributeFactory->getCollection()
->addFieldToFilter(\Magento\Eav\Model\Entity\Attribute\Set::KEY_ENTITY_TYPE_ID, 4)
->addFieldToFilter('is_visible_on_front',1);
To get All product attributes you need to use inject class
app/code/Mendor/Mymodule/Model/Attributes.php
public function __construct(Context $context,
\Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection $coll
){
$this->_coll=$coll;
parent::__construct($context);
}
public function getAllAttributes()
{
$this->_coll->addFieldToFilter(\Magento\Eav\Model\Entity\Attribute\Set::KEY_ENTITY_TYPE_ID, 4);
$attrAll = $this->_coll->load()->getItems();
echo '<pre>'; var_dump($attrAll);'</pre>';
exit;
}
You can do it using the following function:
public function getallattributes()
{
$arr = [];
$attributeInfo = $this->_attributeFactory->getCollection()-
>addFieldToFilter(\Magento\Eav\Model\Entity\Attribute\Set::
KEY_ENTITY_TYPE_I D, 4);
foreach($attributeInfo as $attributes)
{
$attributeId = $attributes->getAttributeId();
// You can get all fields of attribute here
if($attributes->getIsVisibleOnFront()){
$arr[$attributes->getAttributeId()] = $attributes
>getFrontendLabel();
}
}
return $arr;
}

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

Categories