Simple OOP and PHP not working... can anyone help? :) - php

My first foray into OOP with PHP - I am trying to build a query builder object that generates a query based on inputs to the object. I would imagine this is as simple as simple gets.
I expected that the line under the buildQuery function definition $active_value=$this->getActive; would assign 1 to the object's active attribute per the __construct() method... to no avail... what am i doing wrong to achieve the desired result i.e. buildQuery to return
select * from mytable where active=1
TIA!
class queryBuilder {
function __construct(){
$this->active=1;
}
public function active () {
$this->active=1;
}
public function inactive () {
$this->active=0;
}
public function getActive(){
return $this->active;
}
public function setActive($value){
$this->active->$value;
}
public function buildQuery() {
$active_value=$this->getActive();
$query="select * from mytable where active=$active_value";
return $query;
}
}
$init=new queryBuilder();
echo $init->buildQuery();

Response to edit of question
When I run this in a browser, I get select * from mytable where active=1. I assume that is what you need based on your question. If you want active to be quoted (which might be a typo in your original question), then you'll need to replace $query="select * from mytable where active=$active_value"; with:
$query="select * from mytable where active='$active_value'";
// this will output select * from mytable where active='1'
If you want this to be a Boolean in MySQL, then use of 1 vs. 0 should be sufficient, but you can cast:
$query="select * from mytable where active=CAST($active_value as BOOL)";
// this will output select * from mytable where active=CAST(1 as BOOL)
Original text
Well, first you need to use -> instead of =, second you need to call the function:
// not: $active_value=$this=getActive;
$active_value=$this->getActive();
Couple of comments:
As a general rule in OOP, methods are generally broken down to do, get, and set. The names are often different, but they should always be verbs. inactive and active aren't really intuitive.
If you have methods getActive and setActive it is often a good idea to use them to modify the state of the object itself. There are exceptions for performance reasons and the like, but generally it is a good idea and it re-enforces that those methods are there. inactive therefore, should be function inactive(){ $this->setActive(1);}
You should almost never assign a new variable to a pre-defined class. Always declare variables up front when you can (add private $active; at line 1 of the class)
Because $this->active is a boolean, then it should probably be TRUE or FALSE until it is actually added to the query: $active_value = $this->getActive()? 1: 0;

Related

How to make my method working only 1 time?

I have a method in the model Users
public function getRating()
{
$id = \Yii::$app->request->get('id');
$rating = Yii::$app->db->createCommand(
"SELECT * FROM (
SELECT *, (#position:=#position+1) as rate FROM (
SELECT executor_id, SUM(rate) / COUNT(rate) as pts FROM user_replies, (SELECT #position:=0) as a
GROUP BY executor_id ORDER BY pts DESC
) AS subselect
) as general WHERE executor_id = $id"
)->queryOne();
return $rating;
}
and i output result in the view like that
<?php echo $singleUser->getRating()['rate']; ?>
but more qualified coder said me that my query will be executing 2 times. Is that possible to rewrite code so it executes only 1 time?
You seem to be calling $singleUser->getRating() twice.
You could try saving the result in a variable, that way you will not call the database twice.
i.e.
$rating = $singleUser->getRating();
Now it's possible to just use the value from that variable. Saving you a trip to the database.
!is_null($rating)
echo $rating['rate']
As mentioned by thordoor, you can save the value to a variable.
I would just like to add that you could use a private static variable inside the class.
private static $_rating;
And inside your Method you could look inside this variable.
public function getRating(){
if(static::$_rating===null){
// here goes your code
// and an asignment like
static::$_rating = $rating;
}
return static::$_rating;
}
With this way you can have multiple user objects and query the ratings for each of them.
Correct me if I am wrong.

Check for undefined PHP method before calling?

What can I use other than if(!empty( $product->a_funky_function() )) to check if the method is empty before calling it?
I've tried method_exists() and function_exists() and a whole plethora of conditions. I think the issue is that I need to have my $product variable there.
Please help.
A fairly common pattern is to have two methods on your class, along the lines of getField and hasField. The former returns the value, and the latter returns true or false depending whether or not the value is set (where "set" can mean not null, or not empty, or whatever else you might want it to mean).
An example:
class Foo
{
/** #var string */
private $field;
/**
* #return string
*/
public function getField()
{
return $this->field;
}
/**
* #return bool
*/
public function hasField()
{
return $this->getField() !== null;
}
}
This would then be used like:
if ($foo->hasField()) {
$field = $foo->getField();
...
}
Often, like in this example, the has... method often just delegates to the get... method internally, to save duplicating the logic. If the getter contains particularly heavy processing (e.g. a database lookup or API call), you might want to factor in ways to avoid performing it twice, but that's a bit out of scope.
You need absolutely to call it so it can compute the value which it will return, so I think there is no other way to know if it will return something not empty without calling it...
You have to call it.
$result = $product->getFunction();
if(!empty($result)) {
//your code here
}

Different type of object for admin and user

I am building an intranet application and i want to be able to have 2 different types of users a regular user and an admin user. I am trying to figure out what would be the best way to go about doing this. Either to have one object for admin type stuff and then one object for user type stuff. Or combine both of that into one object. But i keep getting stuck and not sure how to go about doing that, or if that is even the best way.
Lets say I have the following situations:
1. query the db to get all tasks for all projects that are active.
Admin Query
2. query the db to get all tasks for all projects that are due today and active.
Admin Query
3. Query the db to get all tasks for a specific project that are active.
Admin Query
User Query
4. Query the db to get all tasks for a specific project that are active and due today.
Admin Query
User Query
5. Query the db to get all tasks for a specific project.
Admin Query
User Query
6. Query the db to get all tasks for a specific project, with different status specified.
Admin Query
7. Any one of those queries has an optional parameter to either get the count or the data.
I started the following object but now im a little stuck as which route to go:
public function getTasks($status, $project, $type = "count", $duetoday = NULL)
{
try
{
if($duetoday != NULL){
$today = date("Y-m-d");
$stmt = $this->db->prepare("SELECT * FROM tasks WHERE status=:status
AND $project=:project AND duedate BETWEEN :duedate
AND :duedate");
$stmt->execute(array(':status'=>$status,':project'=>$project,':duedate'=>$today));
}else{
$stmt = $this->db->prepare("SELECT * FROM tasks WHERE status=:status
AND $project=:project");
$stmt->execute(array(':status'=>$status,':project'=>$project));
}
$tasks=$stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() > 0)
{
if($type == "count"){
return $stmt->rowCount();
}else{
return $tasks;
}
}else{
return false;
}
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
I will start with some words about the single responsibility principle. Basically, this means that an object and it's behaviors should have one responsibility. Here, I think your getTasks method is a good opportunity to refactor some code into better object oriented code.
There are actually many things it is doing:
Generate sql
Execute a query
Control the flow of the program
The method generating sql should not have to worry about it's execution, and the method executing it should not have to worry about getting it. This, as a side effect, will also reduce the nesting in a single method.
There is a lot of code to write, which I'll let you do, but if you create classes that implements those interfaces and a controller to use them, you should be able to get through this and write easier to maintain / refactor code:
interface SqlGenerating {
/**
* #param array $params
* #return string
*/
public function makeSql(array $params);
/**
* #param array $params
* #return array
*/
public function makeValues(array $params);
}
interface DBAccessing {
public function __construct(\PDO $pdo);
/**
* #param string $sql
* #param array $values
* #return PDOStatement
*/
public function getStmt($sql, array $values = []);
}
class Controller {
public function __construct(SqlGenerating $sqlGenerator, DBAccessing $dbAccess) {
// associate to private properties
}
public function getTasks($status, $project, $type = "count", $duetoday = null) {
// this function will use the sqlGenerator and the dbAccess to query the db
// this function knows to return the count or the actual rows
}
}
If you haven't already, this is a good time to learn about type-hinting in functions. This requires your function to be passed an object (or an array) to be assured of the behavior of the function. Also, you will notice that I type-hinted the interfaces into the controller. This is to actually be able to switch classes if ever you need a different one to manage sql and db access.

Decorator case or not?

I have a contract "ArticleStorage" that every storage must be subscribe to be valid for model.
True, this is not the problem, my problem is: pagination ... or "results modification", in this case at fetchAll, i want modify its behavior but without adding parameters, etc
<?php
interface ArticleStorage
{
// public function insert();
// public function update();
// public function delete();
public function fetchAll();
}
class MySQLArticleStorage implements ArticleStorage
{
public function fetchAll()
{
// SELECT * FROM `articles`;
}
}
?>
How my model works.
class ArticlesModel
{
public function __construct(ArticleStorage $storage)
{
}
}
in this case, I expect a "ArticleStorage" but do not know which "Storage" was given, true ... and i want to paginate or apply a results modification, using the Storage.
class MySQLArticleResultsModifier
{
public function __construct(MySQLArticleStorage $storage)
{
}
public function fetchAll()
{
// ...
}
}
In case of a pagination, how i can modify ArticleStorage fetchAll and apply my modified query ?
Is there a case where your model demands that a fetchall on top of another fetchall is possible; I don't think so, infact this is how you decide if you need a decorator or not, by answering this question to yourself
Is the decorator function you are thinking of making works like a decoration{like a real decoration where you can put stars on your christmas tree {decoration1}, and some toys on your tree {decoration2} at the same instance? Otherwise there is no point in making a decorator pattern, The nature of decorator is to decorate the concrete implementations from outside world, and change the output, without being affected by the other decoration being applied to a concrete instance.
Now as to the current implementation, I think #mrhobo is quite right, your fetch function might look like
public function fetch($limit, $order,$sort)
A very smart fetch could also expect the user to send a hashtable of key-value , of the columnname = value of column by using which you can make your own select query on the fly.

Working with dynamic prepared statements in PDO

Sometimes depending on which user type if viewing my page, I need to add in a JOIN, or even just limit the results. Is there a cleaner way of going about it? Should I have separate statements for each type of request instead? What is more "proper"?
Here is what my code ends up looking like:
// Prepare statement
$stmt = $this->db->prepare('
SELECT *
FROM Documents
LEFT JOIN Notes ON ID = D_ID
'.($user_id ? "INNER JOIN Users ON UID = ID AND UID = :userid" : '')."
". ($limit ? 'LIMIT :offset, :limit' : '')
);
// Bind optional paramaters
if ($user_id) $stmt->bindParam(':userid', $user_id, DB::PARAM_INT);
if ($limit)
{
$stmt->bindParam(':offset', $limit[0], DB::PARAM_INT);
$stmt->bindParam(':limit', $limit[1], DB::PARAM_INT);
}
Maybe just wrap the insert strings into their own methods for clarity, like getUserInsertString($user_id), and try to make your quote use more consistent.
Also, are you testing whether $user_id and $limit are defined just by going if ($user_id)? If so, if you had error reporting turned to all, you would get a bunch of undefined variable warnings. You may want to consider using if (isset($user_id)) instead.
I'd create separate (protected) functions, those return a prepared statement that only needs to be executed.
/**
* #returns PDOStatement
*/
protected function prepareStatementForCase1(PDO $dbObject,Object $dataToBind){...}
/**
* #returns PDOStatement
*/
protected function prepareStatementForCase2(PDO $dbObject,Object $dataToBind){...}
Then, I would decide outside, which one has to be called.
You can rebuild, maintain and read the code more easily.
Example:
class Document{
protected $dbObject;
public function __construct(PDO $dbObject){
$this->dbObject=$dbObject;
}
public function doQuery($paramOne,$paramTwo,...){
$logicalFormulaOne=...; // logical expression here with parameters
$logicalFormulaTwo=...; // logical expression here with parameters
if($logicalForumlaOne){
$dbStatement=$this->prepareStatementForCase1($dataToBind);
}else if($logicalFormuleTwo){
$dbStatement=$this->prepareStatementForCase2($dataToBind);
}
$dbResult=$dbStatement->execute();
}
protected function prepareStatementForCase1(Object $dataToBind){
$dbStatement=$this->dbObject->prepare("query string");
$dbStatement->bindParam(...);
return $dbStatement;
}
}
But I would not advice this, when your PDOResult object represents different type of database tuples, or when you return more rows in one of the cases.
What I usually do is that I create a class which represents (in your example) a Document. Only one. I can insert, delete, select, modify by its fields, and handle one item. When I need to (for example) fetch more of them, I create a new class, e.g. DocumentList, which handles a collection of documents. This class would give me an array of Document objects when it fetches more of them.

Categories