PHP Classes - How to call them properly - php

Here's what I'm pretty sure I can do, just don't know how to do it.
class My_Looping_Class {
public function __construct() {
$this->vars = new My_Vars_Class(); //maybe this goes here???
for($y=0;$y<=10;$y++) {
$this->do_loop();
}
}
private function do_loop() {
//in this loop the value of $x in My_Var_Class gets incremented each loop but I'm not exactly
//sure how to call it. Something like this????
$this->vars->x++;
}
}
class My_Var_Class {
public $x = 0;
}
class My_Looping_Class_Copy extends My_Looping_Class {
// Here I need to be able to read and echo the value of x in My_Var_Class each time it
//changes but again, I'm unsure of how to call it.
}
new My_Looping_Class_Copy();
Tried to post this with just the code above and it complained I didn't have enough details. So, here goes:
What I'm attempting to do is to write a web crawler similar to PHPCrawl. In PHPCrawl you basically set the parameters for the crawler (crawl depth, follow redirects, timeout, etc.), set the url, call a "go" function in the main class and it starts crawling pages. As it crawls each page it updates another class that contains all of the result variables, like response time, links found, etc. After it finishes each page crawl, through a class extension, you're able to access all of those variables and process them as you please. After that, it crawls another url it found and updates the result variables.
I tried reading through the code but got lost pretty quick as to how the author did this. The code above is just a very basic example of how PHPCrawl works.
Here's a link to the PHPCrawl example code: http://phpcrawl.cuab.de/example.html What I'm trying to duplicate is the handleDocumentInfo($DocInfo) function.

If I understand you correctly, here's an example of how you can get the value of a property of one class and use it in another one. Extending that other one, instantiating it, and getting the new value of the property:
class My_Looping_Class {
public $xCopy;
public function __construct() {
$varClass = new My_Var_Class();
$this->xCopy = $varClass->x + 10; // Here i add 10 to this class propert 'xCopy'. Loop or do whatever you want with it instead.
}
}
class My_Var_Class {
public $x = 33; // Just some number as an example.
}
class My_Looping_Class_Copy extends My_Looping_Class {
}
$loopClassCopy = new My_Looping_Class_Copy();
echo $loopClassCopy->xCopy; // Should output 43 (33 + 10)
Or see this working example.

Related

Passing parameters in CodeIgniter

I have been banging my head against this problem for about an hour now. I have looked high and low but nothing is working for me. This should be simple and I am sure it is.
I am trying to pass some parameters in CodeIgniter to a URL and nothing seems to be working. Here is my controller:
class Form_controller extends CI_Controller {
public function change($key = NULL) {
if (is_null($key)) {
redirect("reset");
} else {
echo "Hello world!";
}
}
}
Here is my route:
$route['change/(:any)'] = "form_controller/change/$1";
Every time I visit /index.php/change/hello I get the string "Hello world!" but when I visit /index.php/change I got a 404 not found.
What I am trying to do is pass a parameter to my controller for the purposes of checking the DB for a specific key and then acting upon it. If the key does not exist in the DB then I need to redirect them somewhere else.
Any thoughts on this?
Never mind, I figured it out. I ended up making two different routes to handle them, like so:
$route['change'] = "form_controller/change";
$route['change/(:any)'] = "form_controller/change/$1";
And the function in the controller looks like this now:
public function change($key = NULL) {
if (is_null($key)) {
redirect("reset");
} else if ($this->form_model->checkKey($key)) {
$this->load->view("templates/gateway_header");
$this->load->view("forms/change");
$this->load->view("templates/gateway_footer");
} else {
redirect("reset");
}
}
If anyone has a better solution, I am all ears. This worked for me though.
This might help you out
public function change() {
$key = $this->uri->segment(3);
http://ellislab.com/codeigniter/user-guide/helpers/url_helper.html
This allows you to grab the segment easily using the CI url helper
index.php/change/(3RD Segment) this part will go into that variable $key.
This may not be what you are looking for but it is very useful if you are trying to pass two variables or more because you can just grab the segment from the url and store it into the variable

PHP5 getting page for all categories

So this question comes from another i created you can find here But i have changed my code so now it looks something like this:
Car Controller
public function indexAction(){
$category = new Application_Model_CarMapper();
$gcat = $this->getRequest()->getPathInfo();
//get id
$id = $category->find_id_by_name($gcat);
$this->view->title = $category->get_sub_cat_select($id);
}
This is a new function i created inside the mapper:
public function find_id_by_name($name){
$select = $this->getDbTable()->query("SELECT * FROM car_category WHERE category_name = '{$name}'");
$result = $select->fetchAll();
if(!$result) {
return;
}
return $result[0]['ID'];
}
I am testing it out by the title but it just doesnt seem to display at all. I would like it to display the drop down menus for the specific category, e.g
car-live.local/cars/Volvo ---> "Welcome to the Volvo Car Finder"
car-live.local/cars/BMW ---> "Welcome to the BMW Car Finder"
I know it is not working as i have to split down the URL even more, as right now it is finding the id via the URL, but i am unsure how to do this :s Any light you can shed on this would be extremely grateful.. Thanks.
[EDIT]
New code:
public function indexAction(){
$category = new Application_Model_CarMapper();
$gcat = explode("/", $this->getRequest()->getPathInfo());
if(isset($gcat['category_name'])) {
$id = $category->find_id_by_name($gcat);
$this->view->title = $category->get_sub_cat_select($id);
}
}
I'm not sure if I understood correctly your issue, but from code it seems like you're having issues dealing with the URL. So, let's take this example:
car-live.local/car/Volvo
After you get at indexAction you should explode by the /.
This is return an array with all the components of the URL, then you take the last one in this case would be Volvo and send it to your find_id_by_name() method.
My usual approach to this problems is to follow something like:
Explode by slashes;
Get the first one (in this case car and "route" it to a cars class, by sending to the constructor that and the rest of the request;
The car class constructor then takes the next part of the URL Volvo and "routes" it an appropriate method like getVolvo() or whatever you need...
You can route it to what you need, but just try to delegate the responsibilities of processing the URL to the appropriate classes. Example:
/cars/whatEverCar => Should be processed by class car
/bike/whatEverBike => Should be processed by class bike
Hope this helps.
Edit:
Your find_id_by_name() method can have some URL like:
/car/find_id_by_name/Volvo
Am I explaining this well? You can take parts of the URL and call methods directly... and send the rest of the URL.
Edit 2: Code example...
The following code is a very nice solution for your problem:
<?php
// Call this class as soon the site stars
class Router {
public function __construct() {
// In some really cool way get your full URL, for example I'm gonna use a string...
$fullURL = "example.com/Car/findCarById/Volvo";
array_shift($fullURL); // removes "example.com", obvious stuff...
$explodedUrl = explode("/", $fullURL);
$targetClass = $explodedUrl[0]; // Temporary store the target is "Car"
array_shift($fullURL); // Removes "Car", we don't need it anymore...
$target = new $targetClass($fullURL); // call the Car class responsible for handling all the "Car" related stuff!
}
}
class Car {
public function __construct($request) {
// $request is an array with "findCarById", "Volvo"
$targetMethod = $request[0]; // Temporary store the target is "findCarById"
array_shift($request);
$this->$targetMethod($request);
}
private function findCarById($parameter) {
// $parameter is an array with "Volvo"..
// Now to your query and other cool stuff with $parameter[0];
print "I'm the method findCarById() of the class Car called by the main router to find the ID for {$parameter}...";
}
}
?>
If you need to add more functions to your Car class, just add another method and then call it over the URL with his name, same way I did with findCarById().
Warning: This code might have minor bugs, it was written on Notepad and IS NOT tested.

Magento Varien Object not Saving data

I'm trying to use setData in my Address object.
Here is the code:
//code inside another class
$this->getAddress()->setData('abc', 'abc')->collectShippingRates()->save();
class Mage_Sales_Model_Quote_Address extends Mage_Customer_Model_Address_Abstract
{
...
public function collectShippingRates()
{
...
$found = $this->requestShippingRates();
...
return $this;
}
public function requestShippingRates(Mage_Sales_Model_Quote_Item_Abstract $item = null)
{
//I knkow it's getting here, because when I echo 'blablabla', it works.
//When I use $this->setData('abc', 'abc') here, the code bellow print 'abc'
//The problem is when I use setData outside the class
echo $this->getData('abc');exit; //prints nothing
...
}
...
}
As you can see, I setData in my Address model, but inside the class getData returns nothing.
Can someone please explain what's happening?
When I try to use Mage::register, it does not work too.
Possible avenues of exploration.
Your call to getAddress isn't returning a Mage_Sales_Model_Quote_Address object, or is returning a different instance of an address object.
Your call to setData('abc', 'abc') happens later in Magento's code execution than the first call to requestShippingRates.
Code between your call to getAddress and the execution of requestShippingRates is re-instantiating or initializing the address object.
Based on your comments about Mage::register, my money is on number two.

Am I writing procedural code with objects or OOP?

So basically I'm making a leap from procedural coding to OOP.
I'm trying to implement the principles of OOP but I have a nagging feeling I'm actually just writing procedural style with Objects.
So say I have a list of pipes/chairs/printers/whatever, they are all all listed as products in my single table database. I need to build a webapp that displays the whole list and items depending on their type, emphasis is on 'correct' use of OOP and its paradigm.
Is there anything wrong about just doing it like:
CLass Show
{
public function showALL(){
$prep = "SELECT * FROM myProducts";
$q = $this->db-> prepare($prep);
$q->execute();
while ($row = $q->fetch())
{
echo "bla bla bla some arranged display".$row['something']
}
}
and then simply
$sth = new show();
$sth->showAll();
I would also implement more specific display methods like:
showSpecificProduct($id)->($id would be passed trough $_GET when user say clicks on one of the links and we would have seperate product.php file that would basically just contain
include('show.class.php');
$sth = new show();
$sth->showSpecificProduct($id);
showSpecificProduct() would be doing both select query and outputing html for display.
So to cut it short, am I going about it allright or I'm just doing procedural coding with classes and objects. Also any ideas/hints etc. on resolving it if I'm doing it wrong?
As well as the model practices described by #Phil and #Drew, I would urge you to separate your business, data and view layers.
I've included a very simple version which will need to be expanded upon in your implementation, but the idea is to keep your Db selects separate from your output and almost "joining" the two together in the controller.
class ProductController
{
public $view;
public function __construct() {
$this->view = new View;
}
public function indexAction() {
$model = new DbProductRepository;
$products = $model->fetchAll();
$this->view->products = $products;
$this->view->render('index', 'product');
}
}
class View
{
protected $_variables = array();
public function __get($name) {
return isset($this->_variables['get']) ? $this->_variables['get'] : null;
}
public function __set($name, $value) {
$this->_variables[$name] = $value;
}
public function render($action, $controller) {
require_once '/path/to/views/' . $controller . '/' . $action . '.php';
}
}
// in /path/to/views/product/index.php
foreach ($this->products as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}
A better fit would be to implement a repository pattern. An example interface might be
interface ProductRepository
{
public function find($id);
public function fetchAll();
}
You would then create a concrete implementation of this interface
class DbProductRepository implements ProductRepsoitory
{
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function find($id)
{
// prepare execute SQL statement
// Fetch result
// return result
}
public function fetchAll()
{
// etc
}
}
It's generally a bad idea to echo directly from a method or function. Have your methods return the appropriate objects / arrays / whatever and consume those results.
The scenario you are describing above seems like a good candidate for MVC.
In your case, I would create a class strictly for accessing the data (doing selects of product categories or specific products) and then have a different file (your view) take the output and display it.
It could look something like this:
class Product_Model {
public function find($prodId) { ... }
public function fetchAll($category = '') { ... }
public function search($string) { ... }
}
Then somewhere else you can do:
$products = new Product_Model();
$list = $products->fetchAll(37); // get all from category 37
// in true MVC, you would have a view that you would assign the list to
// $view->list = $list;
foreach($ilst as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />\n";
}
The basic principle of MVC is that you have model classes that are simply objects representing data from some data source (e.g. database). You might have a mapper that maps data from the database to and from your data objects. The controller would then fetch the data from your model classes, and send the information to the view, where the actual presentation is handled. Having view logic (html/javascript) in controllers is not desirable, and interacting directly with your data from the controller is the same.
first, you will want to look into class autoloading. This way you do not have to include each class you use, you just use it and the autoloader will find the right file to include for you.
http://php.net/manual/en/language.oop5.autoload.php
each class should have a single responsibility. you wouldn't have a single class that connects to the database, and changes some user data. instead you would have a database class that you would pass into the user class, and the user class would use the database class to access the database. each function should also have a single responsibility. you should never have an urge to put an "and" in a function name.
You wouldn't want one object to be aware of the properties of another object. this would cause making changes in one class to force you to make changes in another and it eventually gets difficult to make changes. properties should be for internal use by the object.
before you start writing a class, you should first think about how you would want to be able to use it (see test driven development). How would you want the code to look while using it?
$user = new User($db_object);
$user->load($id);
$user->setName($new_name);
$user->save();
Now that you know how you want to be able to use it, it's much easier to code it the right way.
research agile principles when you get a chance.
One rule of thumb is that class names should usually be nouns, because OOP is about having software objects that correspond to real conceptual objects. Class member functions are usually the verbs, that is, the actions you can do with an object.
In your example, show is a strange class name. A more typical way to do it would be to have a class called something like ProductViewer with a member function called show() or list(). Also, you could use subclasses as a way to get specialized capabilities such as custom views for particular product types.

PHP OOP need advice

i am building this sms notification system, which will send 10 times free sms based on certain occasion to the web's member, and after a certain member reach 10 times, the system would send a last notification system saying that "this is the last free sms notification", i am currently learning PHP OOP and trying to use an OOP aproach on this
without further a do here's my code:
<?php
class SmsBonus {
//bonus_sms fields = id, member_id, counter, end_status
public static function find_member($id=0){
//query to find a certain member
}
public function add_counter($id=0){
//query to increment the value of counter field
}
public function status_check($id=0){
//query to check whether the given member's counter has reach the number 10
}
public static function send_sms($id, $message){
$found = $this->find_member($id);
$status_check = $this->status_check($id);
if(!empty($found) && !empty($status_check) && $found->counter == 10){
//send the sms notification saying that this member has reach the end of the bonus period
//update this member's end_status table to 1
}else{
//send the regular notification
}
}
}
?>
would this lines:
$found = $this->find_member($id);
$status_check = $this->status_check($id);
work as expected (i cant test this one out because i am currently building this on local)? and is this a best practice regarding OOP aproach ? or am i doing this wrong ?
i need advice, thank you very much.
EDIT:
of course on my original code i declare the class, i am sorry that by not writing it here confuses everybody :D, i am actually looking for a kind of answer (advice) that pointed the way i should implement a best approach (best practice) on my codes (in this case methods), things that i worry about is that i don't meet the requirements such as K.I.S.S or D.R.Y.
UPDATE
i manage to do some modifications based on your suggestions, how is this looks like ?
<?php
class SmsBonus{
//bonus_sms fields = id, member_id, counter, end_status
protected $max_sms = 10;
public $id;
public $member_id;
public $counter;
public $end_status;
public function find_member($id=0){
//query to find a certain member
}
public function add_counter($id=0){
//query to increment the value of counter field
}
public function status_check($id=0){
//query to check whether the given member's counter has reach the number 10
}
public function update_status($id=0){
//query to update when a certain member reach its sms bonus limit
}
protected function can_still_send_sms($member_id){
$found = $this->find_member($member_id);
$status_check = $this->status_check($id);
return !empty($found) && $found->counter < $this->max_sms && !empty($status_check);
}
public function send_sms($id, $message){
$phone = Phone::find_member($id); //
if ($this->can_still_send_sms($id)) {
//send the sms notification saying that this member has reach the end of the bonus period
$this->update_status($id);
}else{
//send the regular notification
$this->add_counter($id);
}
}
}
$sms_bonus = new SmsBonus();
?>
Well, I think OOP is mostly about creating meaningful actions that are easy to reuse and, especially, make it easy to find out what's going on when you revisit your code some months later (or when someone else reads your code, which is more or less the same). Also, when you found your member, you can then perform logic on that, instead of on the id. So, in this case it might be better to create your methods like this, for example:
protected $max_sms_messages = 10;
protected function can_still_send_sms($member){
return !empty($member) && $member->counter < $this->max_sms_messages;
}
public function send_sms($id, $message){
$found = $this->find_member($id);
if ($this->can_still_send_sms($found)) { // or even if($found->can_still_send_sms()), if you want to implement it that way
//send the sms notification saying that this member has reach the end of the bonus period
//update this member's end_status table to 1
}else{
//send the regular notification
}
}
Also, for the record, you can't call non-static methods from static methods.
You need to wrap your code in a class declaration
class SMSNotification {
...
}
And you may also want to create a constructor
function __construct() {
One reason for this is so that you can set private variables to the class when it is instantiated.
you instantiate the class like this:
$sms = SMSNotification()
Will you be connecting this to a database for the counter increment. As what you would normally do with an oop approach is have a seperate class that handles that connection, so that if you wanted to build on this whole project then everything would be connecting to a database the same way.
The two lines of code you pasted are a bit different:
$found = $this->find_member($id);
you have made find_member a static function (which is probably what i would have done) so that you can call the function without create a new class object. That being said it is not of value $this as it is not part of the current instantiated class. So you will need to call it like (using my example of SMSNotification):
$found = SMSNotification::find_member($id);
This tells php to look for a static function called find_member
The other line of code should work fine:
$status_check = $this->status_check($id);
According to OOP you can't call $this->find_member($id) on a static member function. Besides you didn't declare any class at all, so $this is meaningless (as far as I remember PHP). You probalby wanted to declare some SmsClient class which would be initialized from db query filling in member variables. Your static find_member($id=0) function would query db by id and return initialized object of SmsClient with its id = $id
class SmsClient
{
private $id;
private $nSmsSent;
public __construct($id)
{
$res = DAL->GetClient($id);
//initialize vars here
}
public send_sms(...)
{
$this->nSmsSent++;
}
}
Listen to dewi.
Anyway, a nice way to test if you're using the right syntax is commenting out the content of the find_member() and status_check() functions and make them return some arbitrary values: if the values are actually returned, you're doing it right.

Categories