Calling a method on array iteration, from an object - PHP - php

What I'm trying to do, is iterate through an array (Which in my case is a MySql result), and output it, but also do something else with the data at the same.
Doing this using procedural methods is easy - just put it in the foreach loop.
But, I'm wondering if there is a way that it could be integrated into the object.
So, say for example, I wanted to put the first field into a session, I could do this:
<?php
class MyClass {
public $myArray=array();
public function __construct() {
//..
//Mysql query as $stmt
//..
$this->myArray=$stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
$obj=new MyClass;
$i=0;
foreach($obj->myArray as $row) {
?>
<!-- Output HTML formatted data -->
<?
$_SESSION[$i]=$row['firstfield'];
$i++;
}
?>
But, then that takes the task away from the class.
I could put a foreach loop in the class, like so:
<?php
class MyClass {
public $myArray=array();
public function __construct() {
//..
//Mysql query as $stmt
//..
$this->myArray=$stmt->fetchAll(PDO::FETCH_ASSOC);
$i=0;
foreach($this->myArray as $row) {
$_SESSION[$i]=$row['firstfield'];
$i++;
}
}
}
$obj=new MyClass;
foreach($obj->myArray as $row) {
?>
<!-- Output HTML formatted data -->
<?
}
?>
But, now we have 2 loops on the same data-set. Doubling the time to do the same task.
Is there a way to create a method to do something when the array is being looped through? Effectively making it so that the data-set would only have to be looped through once ...
Edit
Also, forgot to mention, the reason I can't build the HTML within the object, is because it will be used on different pages with different HTML layouts.

How about this
<?php
class MyClass {
public $myArray=array();
public $htm = NULL;
public function __construct(&$format=NULL) {
//..
//Mysql query as $stmt
//..
$this->myArray=$stmt->fetchAll(PDO::FETCH_ASSOC);
$i=0;
foreach($this->myArray as $row) {
switch ($format) {
case 'Page1' :
$this->htm .= $this->format1($row);
break;
case 'Page2' :
$this->htm .= $this->format2($row);
break;
default:
$this->htm .= $this->format_default($row);
}
$_SESSION[$i]=$row['firstfield'];
$i++;
}
}
private function format1($row) {
return // formatted html
}
private function format2($row) {
return // formatted html
}
private function format_default($row) {
return // formatted html
}
}
$obj=new MyClass('Page1');
echo $obj->htm;
?>
Alternatively you could subclass MyClass with as many subclasses as you need for the formats you require.
class myBaseClass {
public $myArray=array();
public function __construct() {
//..
//Mysql query as $stmt
//..
$this->myArray=$stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
class format1Class extends myBaseClass
{
public $htm;
public function __construct() {
parent::_construct();
$i=0;
foreach($this->myArray as $row) {
$this->htm .= // format specific to this class
$_SESSION[$i]=$row['firstfield'];
$i++;
}
}
}
class format2Class extends myBaseClass
{
public $htm;
public function __construct() {
parent::_construct();
$i=0;
foreach($this->myArray as $row) {
$this->htm .= // format specific to this class
$_SESSION[$i]=$row['firstfield'];
$i++;
}
}
}
Now depending on which format you require in any script you instantiate the required class.
$obj = new format2Class();
echo $obj->htm;

Related

Decorator Pattern with method relation

I use the design pattern Decorator in PHP, and I've got a structure problem.
Here's a simple example to illustrate my problem :
interface MyInterface {
function showUsers($array);
function showUser($i);
}
class MyCLass implements MyInterface {
function showUsers($array)
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo $i;
}
}
class MyCLassDecorator implements MyInterface {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUsers($array)
{
$this->inner->showUsers($array);
}
function showUser($i)
{
echo "User: $i";
}
}
class MyCLassDecorator2 implements MyInterface {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUsers($array)
{
$this->inner->showUsers($array);
}
function showUser($i)
{
$this->inner->showUser($i);
echo " is wonderful";
}
}
$myClass = new MyCLassDecorator2(new MyCLassDecorator(new MyCLass()));
$myClass->showUsers(["Alfred", "Bob", "Claire"]);
With this code, the methods showUser of MyClassDecorator & MyClassDecorator2 will never be called.
What can I do?
Is it forbidden to call another method of the same class? (Not really convenient to split my code)
Is there another way to do this?
Should I create one interface by method ?
Thanks a lot :)
EDIT:
Here is the solution that I finally used, although I'm not really satisfied of it...
I split my code not in methods but in interfaces(services)
Here it is :
interface IShowUsers {
function showUsers($array);
}
interface IShowUser {
function showUser($user);
}
class Services {
static $showUsers;
static $showUser;
}
class MyShowUsers implements IShowUsers {
function showUsers($array)
{
foreach($array as $toto) {
Services::$showUser->showUser($toto);
}
}
}
class MyShowUser implements IShowUser {
function showUser($user)
{
echo $user;
}
}
class MyShowUserDecorator implements IShowUser {
private $inner;
public function __construct(IShowUser $inner)
{
$this->inner = $inner;
}
function showUser($user)
{
echo "User: ";
$this->inner->showUser($user)
}
}
class MyShowUserDecorator2 implements IShowUser {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUser($user)
{
$this->inner->showUser($user);
echo " is wonderful";
}
}
$myClass = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));
Services::$showUsers = new MyShosUsers();
Services::$showUser = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));
Services::$showUsers->showUsers(["Alfred", "Bob", "Claire"]);
If you have a better solution, I will be happy to know it :)
Of course, I use the decorator pattern to use these decorators in different ways in many projects like in these exemples:
//no decorators
Services::$showUser = new MyShowUser();
//only the first
Services::$showUser = new MyShowUserDecorator(new MyShowUser());
//only the second
Services::$showUser = new MyShowUserDecorator2(new MyShowUser());
So the extend not seems to be a good solution.
Thanks a lot again for giving the right way to do this :)
It seems to me you need to re-think this a bit. If you can provide a clear picture of what you're trying to accomplish then we can provide more insight. But to answer your question directly you can extend the class and then override the method.
http://sandbox.onlinephpfunctions.com/code/61c33b0ce98631986134bf78efcd0391f9b9ab67
<?php
interface MyInterface {
function showUsers($array);
function showUser($i);
}
class MyCLass implements MyInterface {
function showUsers($array = ["Alfred", "Bob", "Claire"])
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo $i;
}
}
// Extend the class in order to override the methods.
class MyCLassDecorator extends MyCLass {
// Also, try removing this method to see what it does.
function showUsers($array = [1,2,3])
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo "c'est la fete chez $i";
}
}
$myClass = new MyCLassDecorator();
$myClass->showUsers();
EDIT
Not sure if I'm being clear or not but the issue is you're expecting inheritance behaviour without using inheritance. How is MyCLass supposed to know about MyCLassDecorator::showUser?
foreach($array as $toto) {
// The issue is this line. You're mixing `decorator` and `inheritance`.
// You should re-think your design. This will not work.
$this->showUser($toto);
}

Yii function in layout file

I'm using Yii and I'm new to it.
I have a default main.php layout file and i need to make some data extractions from DB and cookies.
I've written 2 functions:
public function getRegionId() {
if(isset(Yii::app()->request->cookies['region_id'])) {
$sk = Yii::app()->request->cookies['region_id']->value;
settype($sk,integer);
return $sk;
} else {
return 1;
}
}
public function regionId2region($id) {
if(empty($id) or gettype($id)!=='integer') {
return null;
} else {
$reg = Regions::model()->findAll(array(
'condition'=>"alive=1 AND id=".$id,
));
return $reg;
}
}
Now it is not working in any controller. My question is: is it possible to make functions in the layout file or is there a way to pass data to layout file (so that it displays in all controllers)?
Move methods into Regions model and make it static. Or Create Helper class? contains just static methods.
class RegionHelper {
public static function getRegionId() {
if(isset(Yii::app()->request->cookies['region_id'])) {
return (int)$Yii::app()->request->cookies['region_id']->value;
}
return 1;
}
public static function regionId2region($id) {
if(empty($id) or gettype($id)!=='integer') {
return null;
} else {
$reg = Regions::model()->findAll(array(
'condition'=>"alive=1 AND id=".$id,
));
return $reg;
}
}
}
You can use BeforeAction in your controller, like this:
protected function beforeAction($action) {
//Define your variable here:
public $yourVaribale;
//do your logic and assign any value to variable
}
Now, you can use this variable in the view file:
view:
<h1><?php echo $this->yourVariable; ?></h1>
If your functions are located in the controller that calls the view, you could use the $this reference to access the function. Note the public access of the function.
class UserController extends Controller
{
// :
// :
public function fullName($a,$b) {
return $a.' '.$b;
}
}
...and in your view ...
<h1>Test for <?php echo $this->fullName('Tom', 'Jones'); ?></h1>
If the function is in your model, there are a few choices.
class User extends Activerecord
{
// :
// :
public function fullName($a,$b) {
return $a.' '.$b;
}
}
You could pass the model through the render function,
class UserController extends Controller
{
// :
// :
public function actionDisplayView {
$userModel = User::model()->findByPK(1);
$this->render('user_view', array('model' => $model));
}
}
and directly call the function in the view.
< h1 >Test for <?php echo $model->fullName('Tom', 'Jones'); ?>< / h1 >
or, if you did not pass the function, you could call the function in the view (or helper classes). Watch the scope.
class User extends Activerecord
{
// :
// :
// NOTE: You won't have access to $this.
static public function fullName($a,$b) {
return $a.' '.$b;
}
}
and in the view
< h1 >Test for <?php echo User::fullName('Tom', 'Jones'); ?>< /h1 >

While in zend framework

Good morning to everyone here, I try to make a query of the following form with zend framework but I can not, I want to use while because with foreach already do, leave my code to see where I'm wrong:
Model.php
<?php
class Application_Model_Datas
{
public function listar()
{
$db = Zend_Db_Table::getDefaultAdapter();
$select = $db->select()
->from('album');
return $db->fetchAll($select);
}
}
Index.phtml
<?php
//And your view looks like this.
while ($select = $this->datos){
print_r($results);
}
?>
Controller.php
<?php
class IndexController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$table = new Application_Model_Datas();
$this->view->datos = $table->listar();
}
}
The problem is it does not show me any errors or data or anything
Your code has no sense/effect
<?php
//And your view looks like this.
while ($select = $this->datos){
print_r($results); //Normally you get in an infinite loop
}
?>
You just need to iterate over a simple array :
$i = 0;
while($i < count($this->datos)) {
print_r($this->datos[$i++]); //Getting current element, and incremeting counter
}
Hope it helps.

Pass variables from class instance to its extended method

I'm trying to pass a variable to a method in an extended class, but it's not working.
Here's the sample code:
class set2 extends set1
{
function Body($variable) {
}
}
$start2 = new set2();
$start2->Body('some text');
The last line is the part I'm trying to get to work. I'm not sure if I should have a constructor instead to do it or how it's best to get it to work.
I figured it out. I just added a public variable instead and passed its value like this:
class set2 extends set1
{
public $variable = NULL;
function Body() {
echo $this->variable;
}
}
$start2 = new set2();
$start2->variable = 'Some Text';
Three different ways of doing what I think you're trying to do:
class set1
{
protected $headVariable;
function Head() {
echo $this->headVariable;
}
function Body($variable) {
echo $variable;
}
function Foot() {
echo static::$footVariable;
}
}
class set2 extends set1
{
protected static $footVariable;
function Head($variable) {
$this->headVariable = $variable;
parent::Head();
}
function Body($variable) {
parent::Body($variable);
}
function Foot($variable) {
self::$footVariable = $variable;
parent::Foot();
}
}
$start2 = new set2();
$start2->Head('some text');
$start2->Body('some more text');
$start2->Foot('yet more text');

PHP class: Unable to access array in another function

I tried a lot of search but unable to figure out why array $wordlinks in function DoWordLink is not carrying values from function __construct. PHP class code as below:
<?php
class autolinkkeyword
{
public $wordlinks = array();
public function __construct(){
$query = mysql_query("SELECT keyword FROM library");
while ($row = mysql_fetch_array($query))
{
$this->wordlinks [$row["keyword"]] = $row["keyword"];
}
}
public function linkkeywords ($posts)
{
function DoWordLink($match)
{
$rpl=$match[1];
if(isset($wordlinks[$rpl]))
{
$kword = $this->wordlinks[$rpl];
$rpl="<a class=\"keyword_link\" href=\"#\" onclick=\"popup('popUpDiv');
ajax_loadContent('kword', 'library.php?keyword=$kword')\">$kword</a>";
unset($this->wordlinks[$match[1]]);
}
return $rpl;
}
$wl=array_keys($this->wordlinks);
$pm="/((?<=\s|^)(?:" . implode('|',$wl) .")(?=\.|\!|\?|\,|\'|\s|$))/im";
foreach($posts as $key => $mainbody)
{
$mainbody=preg_replace_callback($pm, 'DoWordLink', $mainbody) ;
echo $mainbody;
}
}
}
?>
You can make it an actual method of that class and call it using this method:
http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback
like:
preg_replace_callback($pm, array($this, 'DoWordLink'), $mainbody);
Change DoWordLink function so it is part of the class like:
class autolinkkeyword
{
function DoWordLink($match)
{
$rpl=$match[1];
if(isset($this->wordlinks[$rpl]))
{
$kword = $this->wordlinks[$rpl];
$rpl="<a class=\"keyword_link\" href=\"#\" onclick=\"popup('popUpDiv');
ajax_loadContent('kword', 'library.php?keyword=$kword')\">$kword</a>";
unset($this->wordlinks[$match[1]]);
}
return $rpl;
}
}
aren't you missing a "this->" construct here? if(isset($this->wordlinks[$rpl]))
Use the $this everywhere you refer to $wordlinks.
$this->wordlinks
You need to access the property in your linkkeywords-method with the object-accessor, too!
public function linkkeywords ($posts)
{
// Here use $this->wordlinks not $wordlinks
}

Categories