How do I declare 'sub-objects' in PHP - php

I'm relatively new to OOP in PHP, and I'm not sure if what I'm trying to do is possible or recommended. In any case, I can't figure it out. I'd appreciate any pointers to tutorials or documents which might help - I'm not expecting a full-blown answer here.
I have a system in which each user has a number of 'Libraries'. Each Library contains a number of 'Elements'.
DB set up is as follows:
user_libraries
- id (unique)
- user_id (identifies user)
- name (just a string)
elements
- id (unique)
- content (a string)
library_elements
- id (unique)
- library_id
- element_id
where library_id is the id from user_libraries, and element_id is that from elements.
I want to be able to access a given user's library, and their elements.
I've set up the library class, and can use it to retrieve the list of libraries (or a sub-list).
I do this like this:
$mylibraryset = new LibrarySet();
$mylibraryset->getMyLibraries();
which gives (when I use print_r):
LibrarySetObject (
[user_id] => 105
[data_array] => Array (
[0] => Array (
[id] => 1
[user_id] => 105
[type] => 1
[name] => My Text Library
)
[1] => Array (
[id] => 2
[user_id] => 105
[type] => 2
[name] => Quotes
)
)
)
Now, what I'd like to be able to do is for each of those libraries (the elements in data_array), to retrieve all the elements.
The best idea I've had so far is to do something like:
foreach($mylibrary->data_array as $library) {
$sublibrary = new Library();
$sublibrary -> getAllElements();
}
where Sublibrary is another class which has the function getAllElements. I can't quite get it to work though, and I'm not sure I'm on the right lines...
Is there a way that I can then end up being able to do something like this:
$mylibrary->sublibraries[0]->element[0]
to retrieve a specific element?
As I say, I don't expect a full-blown explanation here - just pointers to get me started.

<?php
class Library {
public $element;
public $data;
public function __construct($sublibrary) {
$this->data = $sublibrary;
}
public function getAllElements() {
// populate $this->element using $this->data
}
}
class LibrarySet {
public $user_id;
public $data_array;
public $sublibraries;
public function getMyLibraries() {
// populate $this->data_array
$this->sublibraries = Array();
foreach($this->data_array as $index => $sublibrary) {
$this->sublibraries[$index] = new Library($sublibrary);
$this->sublibraries[$index]->getAllElements();
}
}
}
$mylibraryset = new LibrarySet();
$mylibraryset->getMyLibraries();
$mylibraryset->sublibraries[0]->element[0]
?>

Related

Optional setter

How can I set a specific setter inside of a child class to be optional
I have a web page build with PHP that prints a recursive objects array, I have a parent class called Person and a child class called Teachers.
Now the teachers can also teach another teacher, I have divided my teachers with the following types "Master, Senior, Junior", and as a matter of fact I already solve that problem, I can see an array of objects within an array of objects, something like this:
Array
(
[0] => Teacher Object
(
[subject:Teacher:private] => Matematicas
[teacherType:Teacher:private] => Master
[teachers:Teacher:private] => Array
(
[0] => Teacher Object
(
[subject:Teacher:private] => Matematicas 2
[teacherType:Teacher:private] => Senior
[teachers:Teacher:private] => Array
(
[0] => Teacher Object
(
[subject:Teacher:private] => Ciancias 1
[teacherType:Teacher:private] => Junior
[teachers:Teacher:private] => Array
(
)
[id:Person:private] => 7
[name:Person:private] => Pedro
[nickname:Person:private] => PedroBoy
)
)
I imagine you get the idea, my problem is that the junior teacher does not receive any teachers array, because he is a jnuior teacher and he can't teach teachers yet. But if I write nothing on it, it will launch an error saying that the teachers array of junior teachers is undifined and it will assign an empty teachers array object to it.
Is there any way to nake that specific setter optional?.
Here is my PHP Code:
class Teacher extends Person{
private $subject = '';
private $teacherType = '';
private $teachers = array();
public function __construct($data) {
parent::__construct($data);
$this->setSubject($data["subject"]);
//OPTIONAL
$this->setTeachers($data["teachers"]);
$this->setTeacherType($data["type"]);
}
?>
Maybe a simple if statement?
class Teacher extends Person
{
private $subject = '';
private $teacherType = '';
private $teachers = array();
public function __construct($data)
{
parent::__construct($data);
$this->setSubject($data["subject"]);
if (isset($data['teachers']))
$this->setTeachers($data["teachers"]);
$this->setTeacherType($data["type"]);
}

PHP Array Check the attribute, return value based on attribute

I am trying to return pull a value based on an attribute from an array, and it seems straight forward enough but I can't seem to nail down the correct way to accomplish this.
Here is the array I am trying to pull from:
[1] => InfoOptions Object
(
[description] => INFO
[optSequence] => 2
[eqpObject] => CUSTOMER NTWK ENG
[attribute] =>
[eqpValue] =>
[dlrSequence] => 10
)
[2] => InfoOptions Object
(
[description] =>
[optSequence] => 3
[eqpObject] => CUSTOMER TEST
[attribute] => CUSTOMER
[eqpValue] => Jon Doe
[dlrSequence] => 10
)
Here is what I have so far:
if (is_array($provisionCVResult->path->infoOptions-_InfoOptions)) {
foreach ($provisionCVResult->path->infoOptions ->InfoOptions as $cv_obj) {
$CVA = array();
$result = null;
foreach ($CV_obj as $value) {
if($value['attribute'] == 'CUSTOMER') {
$CVA["eqpValue"] = $cv_obj->eqpValue;
break;
}
}
$this->cvArrayDataList[] = $CVA;
}
}
Where am I going wrong?
If $provisionCVResult->path->InfoOptions is an array, it does not make sense to write $provisionCVResult->path->InfoOptions ->InfoOptions in the foreach
EDIT: I red in the comments that the array is $provisionCVResult->path->InfoOptions->InfoOptions
PHP is case sensitive so $cv_obj and $CV_obj are two different variables
The second foreach is not needed
So, assuming $provisionCVResult->path->InfoOptions->InfoOptions is returning an array of InfoOptions Object, I think you should do something like this:
if (is_array($provisionCVResult->path->InfoOptions->InfoOptions))
{
$result = null;
foreach($provisionCVResult->path->InfoOptions->InfoOptions as $cv_obj)
{
if($cv_obj->attribute == 'CUSTOMER')
{
$this->cvArrayDataList[] = array("eqpValue" => $cv_obj->eqpValue);
}
}
}
Having a quick look, try changing
$value['attribute'] == 'CUSTOMER'
To
$value->attribute == 'CUSTOMER'
As the element is an "InfoOptions object" and not an array.
Note I would also recommend using strict comparison, e.g '===' instead of '=='.

symfony propel : wrongly populated object with criteria addJoin

This is my first question here, so please try to be patient with me :)
I've stumbled upon a weird behavior populating an object.
I started to convert the objectQuery::create()-> ... ->find() methods used in my project to $c = new Criteria(), $c-> ... objectPeer::doSelect($c) since I've been told Queries shouldn't be used when criteria can be.
I have a function, that returns all the prices of items from the shop. Or at least did. The thing that I cannot figure out is this:
the old code:
static public function shopGetPrices($id){
$prices = itemPriceQuery::create()->
addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id)->find();
return $prices;
}
returns correctly populated PropelObjectCollection object, through which i can go with foreach, and get/set the itemPrice objects and attributes i need.
now, the new code:
static public function shopGetPrices($id){
$c = new Criteria();
$c->addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id);
return self::DoSelect($c);
}
returns an array of itemPrice objects, but they are populated with item values related to itemPrice objects through join. that means : when I call print_r(self::DoSelect($c)); it prints
Array
(
[0] => ItemPrice Object
(
[startCopy:protected] =>
[id:protected] => 47 <- id of joined item
[item_id:protected] => 9 <-foreign key to category object of joined item
[price:protected] => 0
[unit:protected] => Axe <- name of item, not unit (unit is like 'golden', 'iron', 'wood' or whatever )
[active:protected] =>
[collItemsOrder:protected] =>
[collItemsOrderPartial:protected] =>
[alreadyInSave:protected] =>
[alreadyInValidation:protected] =>
[polozkyObjednavkasScheduledForDeletion:protected] =>
[prisadyPolozkyObjednavkasScheduledForDeletion:protected] =>
[validationFailures:protected] => Array()
[_new:protected] =>
[_deleted:protected] =>
[modifiedColumns:protected] => Array()
[virtualColumns:protected] => Array()
)
[1] => ItemPrice Object
(
...and so on.
There is probably some crucial difference between criteria and query object, that I'm missing. I searched on Google, StackOverflow, and who knows where, but I didn't find anything resembling a solution to this.
This guy/gal had a vaguely similar problem, but I didn't use addSelectColumn with my criteria, so it's been another dead end for me.
Can anyone please point me in the right direction?
I found the problem. It was that I had overriden method do select in itemPricePeer class
public static function doSelect(Criteria $criteria, PropelPDO $con = null){
$critcopy = clone $criteria;
$critcopy->add(self::ACTIVE, 1);
return self::populateObjects(itemPeer::doSelectStmt($critcopy, $con));
}
I switched self/itemPricePeer with itemPeer in populateObjects arguments. silly me :-/ Thanks for your responses anyway j0k.

Modify PHP Object Property Name

In PHP is it possible to change an Objects property key/name? For example:
stdClass Object
(
[cpus] => 2
[created_at] => 2011-05-23T01:28:29-07:00
[memory] => 256
)
I wish to change the key created_at to created in the Object leaving an object that looks like:
stdClass Object
(
[cpus] => 2
[created] => 2011-05-23T01:28:29-07:00
[memory] => 256
)
$object->created = $object->created_at;
unset($object->created_at);
Something like an adapter class may be a more robust choice though, depending on where and how often this operation is necessary.
class PC {
public $cpus;
public $created;
public $memory;
public function __construct($obj) {
$this->cpus = $obj->cpu;
$this->created = $obj->created_at;
$this->memory = $obj->memory;
}
}
$object = new PC($object);
No, since the key is a reference to the value, and not a value itself.
You're best off copying the original, then removing it.
$obj->created = $obj->created_at;
unset(obj->created_at);
Its similar to #deceze adapter, but without the need to create an extra class
$object = (object) array(
'cpus' => $obj->cpus,
'created' => $obj->created_at,
'memory' => $obj->memory
);

Get a PHPActiveRecord result as simple array, not array of objects

I would like to have a simple a method, that can give back PHP Activerecord results as simple/associative arrays, not an array of ActiveRecord Objects.
In Ruby I believe this is done perhaps with .map() method. (I am not a Ruby guy...)
What I want is a simple method call, like toArray() in Zend_DB_Table, not a foreach, or something like that, but I can't seem to find it in their docs.
In PHP ActiveRecord getting a result is really easy:
$settings = SystemSettings::all();
But it gives back something like this:
[0] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => author
[value] => Hawle
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
[1] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => base_url
[value] => example.com
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
While this is really great in many cases, here, I would just like to have a simple array, like this:
Array
(
[author] => Hawle
[base_url] => example.com
)
I had a similar issue hopefully this can help someone else who stumbles on it. Obviously, this is specific to phpactiverecord.org.
In /lib/Model.php I added the following function:
public function to_array(array $options=array())
{
return $this->serialize('array', $options);
}
In /lib/Serialization.php I added the following class
class arraySerializer extends Serialization
{
public static $include_root = false;
public function to_s()
{
return self::$include_root ? array(strtolower(get_class($this->model)) => $this->to_a()) : $this->to_a();
}
}
I can then call ->to_array() and get an array back.
Hope this helps!
I was searching for the answer to this question in order to produce an array of results that could be easily json-encoded and sent as the response to an ajax call. I wanted only the attributes of each object in the array of results.
Unfortunately, you can't just call to_json() on each result and then json-encode the entire thing; you end up with double-encoding. Fortunately, though, the function and class posted by #willwashburn to solve this problem have now been included in php-activerecord, though they don't seem to have made it into the online documentation.
To return an array of results, do the following:
$data = MyModel::find('all');
foreach ($data as &$result) {
$result = $result->to_array();
}
Your entire result set will now be an array of arrays, containing only the attributes of each object. You can then do something like
echo(json_encode($data));
if you want to send it as the response to an ajax call.
This is my solution:
$posts = Post::find('all');
$arrayResult = array_map(function($res){
return $res->attributes();
}, $posts);
printf('<pre>%s</pre>', print_r($arrayResult, true));
class MyPHPActiveRecord extends PHPActiveRecord {
public function toJSON() {
return json_encode(get_object_vars($this));
}
}
You could do it like this:
funciton ar2array($settings){
$arr = array();
foreach($settings as $fieldObj){
$fieldName = $fieldObj->attributes["param"];
$fieldValue = $fieldObj->attributes["value"];
$arr[$fieldName] = $fieldValue;
}
return $arr;
}
$resultAsYouWant = ar2array($settings);
Hope this helps. Cheers
PS: If ->attributes is private use its accesor method (there must be one) as ->getAttributes() or equivalent.
I found this looking for solution of the same problem that I encountered using Yii framework - there is simplier way to do this in Yii.
$posts = Posts::model()->findAll();
foreach($posts as $result)
{
print_r($result->attributes);
}
It prints simple array as requested:
Array
(
[id] => 1
[title] => Title
[text] => Text
)
Hope it helps somebody.
My solution:
Added the following method to the utils class found in lib\Utils.php
public static function results_to_json($data)
{
$arr = array();
if(count($data)>0){
foreach($data as $row){
array_push($arr, $row->to_array());
}
}
return json_encode($arr);
}
Call by:
echo \ActiveRecord\Utils::results_to_json($dataobject);
Obviously this is no longer relevant to the OP; however, considering that it still took me over an hour to find a solution for this (no thanks to php-activerecords docs), this may help someone else.
$r = Model::find('$id')->attributes();
$a = [];
foreach ($r as $k => $v)
{
$a[$k] = $v;
}
Perhaps not the most elegant, but works perfectly.

Categories