Catchable fatal error in MVC framework - php

I am trying to set up a simple MVC framework for my PHP script.
Model ('conference'):
public function getConferenceLogs($pin){
$stmt_conferences = $this->db->prepare(
'SELECT
date_created,
timediff(date_completed, date_created) AS duration,
RecordURL,
conference_sid
FROM
conference
WHERE
pin=:pin');
$stmt_conferences->bindParam(':pin', $pin);
$stmt_conferences->execute();
$count = $stmt_conferences->rowCount();
if ($count !== 0) {
$row = $stmt_conferences->fetch();
return $row;
}
return false;
}
Controller:
function conference_history()
{
Auth::handleLogin();
$this->loadModel('conference');
$row = $this->model->getConferenceLogs(Session::get('user_pin'));
$this->view->row = $row;
$participant = $this->model->getParticipantLogs(Session::get('user_pin'));
$this->view->participant = $participant;
$this->view->render('account/conference_history');
}
View:
<?php
var_dump($this->row);
?>
I know this query in the model should return at least 7 records, when executed outside an MVC framework in a conventional format (https://stackoverflow.com/a/20275597/2429989)
However, a var_dump($this->row) gives the following results:
object(stdClass)[5]
public 'date_created' => string '2013-10-29 19:20:37' (length=19)
public 'duration' => string '00:03:42' (length=8)
public 'RecordURL' => string '' (length=0)
public 'conference_sid' => string '1c540158-40cf-11e3-b4cc-81e296145de2' (length=36)
Which I assume means there is only one record? I want to display all 7 records; have I set up the query wrong or is it my echo statement? I want to display all 7 records for each property (e.g. print $this->row->date_created).

Looking at your var_dump, $this->row is just an object and it cannot be casted to a string. So, you'll want to access the public properties as such:
<?php
print $this->row->date_created;
...//repeat as needed
?>
Or if you have more than one row object in some sort of collection
<?php
foreach($this->row_collection->row as $row){
print $row->date_created;
...//blah blah blah
}

Related

Is Api Result the same as the frontend result?

In my code I am trying to get access my data bank through query builder, everything works I am able to get access to everything as a string (which this is what I want), everything but my date is returned as a class DateTime object in my Frontend, the intersting part for me through Api I am getting my date as a string and not as a class DateTime object and I cant understand why I am getting two different results when I am using the same methods same query builder and my Question is why am I getting two different results? is it possible to get different result through Api? and if so why? and is there a way to convert the class DateTime object to a string?
Api Controller
public function indexAction()
{
$request = $this->Request();
$limit = $request->getParam('limit', 1000);
$offset = $request->getParam('start', 0);
$sort = $request->getParam('sort', []);
$filter = $request->getParam('filter', []);
$result = $this->resource->getList($offset, $limit, $filter, $sort);
$view = $this->View();
$view->assign($result);
$view->assign('success', true);
}
Fronend Controller
public function listAction()
{
$feedback= $this->resource->getList(0, 10, null, null);
$this->View()->assign('feedback', $feedback);
}
QueryBuilder
protected function getBaseQuery()
{
$builder = $this->getManager()->createQueryBuilder();
$builder->select(['feedback', 'user_id.firstname','user_id.lastname',])
->from(FeedbackModel::class, 'feedback')
->leftJoin('feedback.customer', 'user_id');
return $builder;
}
getList function
public function getList($offset, $limit, $filter, $sort)
{
$this->checkPrivilege('read');
$builder = $this->getBaseQuery();
$builder->setFirstResult($offset)
->setMaxResults($limit);
if (!empty($filter)){
$builder->addFilter($filter);
}
if (!empty($sort)){
$builder->addOrderBy($sort);
}
$query = $builder->getQuery();
$query->setHydrationMode($this->getResultMode());
$paginator = $this->getManager()->createPaginator($query);
$totalResult = $paginator->count();
$feedback = $paginator->getIterator()->getArrayCopy();
return ['data' => $feedback , 'total' => $totalResult];
}
Api result
data
0
0
id 1
feedback "this shop is boring"
date "2022-12-07T00:00:00+0100"
public true
firstname "some"
lastname "thing"
total 1
success true
Frontend Result
0 => Array (3)
0 => Array (4)
id => 1
feedback => "this shop is boring"
date => DateTime Object (0)
public => true
firstname => "some"
lastname => "thing"
total => 1
->nocache = null
How I fixed my Problem and what it was:
With the help of #ADyson I found out what the problem was. I was tackling the problem from the wrong way though I didn't need to convert my DateTime to string neither in my Model, in my Controller or my Query-builder the only problem was the way I was calling it, there is a way of calling date objects like this in smarty and its by using |date:'dd.MM.y' in my case it was {$feedbacks.date|date:'dd.MM.y'} this get the date inside of the class and converts it to a string at the same time and like that I got to call the date that I want.
To answer my Original Question:
Api and Frontend don't give different result but a different Format which is for the human eye a bit different with the use of different Tools such as PHPStorm Debugger, Postman and Smarty Debugger I got to see the different result, why I am getting these Kind of results and the data inside of the class DateTime in my case.
what helped me find a solution my to problem
PHPStorm Debugger.
Smarty Debugger
Postman

Function that can take as an argument either id or array with that id

I have a function that takes user id as an argument, and returns array of user data:
function user_get_data( $user_id ) {
$query = "SELECT * FROM users WHERE id = '$user_id'";
...
return $user_data; // associative array
}
Usage:
$user_data = user_get_data( 123 );
var_dump( $user_data );
// Outputs:
// array (size=2)
// 'id' => int 123
// 'name' => string 'Juan Vitelli' (length=12)
And I have a function that takes user id, and returns count of posts of that user:
function user_get_post_count( $user_id ) {
$query = "SELECT COUNT(*) FROM posts WHERE user_id = '$user_id'";
...
return $post_count;
}
Now I want to rewrite user_get_post_count() function so it can take as an argument either user id directly, or user data array returned by user_get_data() function, which contains that id. Something like this...
function user_get_post_count( $user_data_or_id ) {
// get user id
if( is_array( $user_data_or_id ) ) {
$user_id = $user_data_or_id[ "id" ];
} else {
$user_id = $user_data_or_id;
}
// get post count
$query = "SELECT COUNT(*) FROM posts WHERE user_id = '$user_id'";
...
return $post_count;
}
I just want to know if something like this is considered as good practice or if there is better way. If it is good practice my next question is if $user_data_or_id is suitable variable name for what I am doing.
There are different approaches to this. You may want to read a bit about ORM, Active Record, Data Mapper, Query Object.
In your context, I don't see a point of passing an array just to extract the "user_id" from it. If you are passing an array, i would say that this is indicating that you're looking for "posts" by more than one "user_id", or according to a specific criteria. That is, in another more general context, you are building your query based on the input parameter. And in that case, it would indeed be better to pass a filter array.
For example, your array might look like this:
array('user_id' => 7, 'title'=>'abc','ts_created'=>1234567, 'published'=>1, ...)
And using some SQL syntax builder, you would end up with a query like this:
SELECT
*
FROM
`posts`
WHERE
`user_id` = 7 AND
`title` LIKE '%abc%' AND
`ts_created` >= 1234567 AND
`published` = 1
.
.
.
As you can see, this would return a resultset that matches your search criteria. If you criteria specifies a "userID", then you would get back "posts" only by this user in the results.
To do this in OOP, there's also several approaches. If you want to map the above to a simple "User" class, you could do:
class User{
public function getByID($userID){
//sql query
$query = "SELECT FROM users where user_id = $userID"
//execute query and return results
}
}
But as you can see, this is not very flexible if you want to specify more filter criteria for the SQL query. To make it more flexible, taking "Posts" as an example, you can create a "Post" class:
class Post{
/*
* This is not a working code, just an example to give you an idea.
*/
protected $mSQLBuilder;
protected $mTable = 'posts';
public function __construct(){
$this->mSQLBuilder = new SQLBuilder($this->mTable);
}
public function search($filter = array()){
//
$criteria = array('fields'=>array('*'),'filters'=>$filter);
//
$query = $sqlBuilder->build($criteria);
//
return $query->execute()->fetchAll();
}
public function count($filter){
//
$criteria = array('fields'=>array('count(*)'),'filters'=>$filter);
//
$query = $sqlBuilder->build($criteria);
//
return $query->execute()->fetch();
}
public function setSQLBuilder($builder){
$this->sqlBuilder = $builder;
}
}
Make sure you do a bit of reading about ORM and design patterns.

How do I get database column names in Laravel?

How can I get column names of a table in an array or object in Laravel 4, using Schema, DB, or Eloquent?
It seems that I can't find a ready to use function, maybe you have some custom implementations.
New Answer
At the time I gave this answer Laravel hadn't a way to do this directly, but now you can just:
$columns = Schema::getColumnListing('users');
Old Answer
Using attributes won't work because if you do
$model = new ModelName;
You have no attributes set to that model and you'll get nothing.
Then there is still no real option for that, so I had to go down to the database level and this is my BaseModel:
<?php
class BaseModel extends \Eloquent {
public function getAllColumnsNames()
{
switch (DB::connection()->getConfig('driver')) {
case 'pgsql':
$query = "SELECT column_name FROM information_schema.columns WHERE table_name = '".$this->table."'";
$column_name = 'column_name';
$reverse = true;
break;
case 'mysql':
$query = 'SHOW COLUMNS FROM '.$this->table;
$column_name = 'Field';
$reverse = false;
break;
case 'sqlsrv':
$parts = explode('.', $this->table);
$num = (count($parts) - 1);
$table = $parts[$num];
$query = "SELECT column_name FROM ".DB::connection()->getConfig('database').".INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'".$table."'";
$column_name = 'column_name';
$reverse = false;
break;
default:
$error = 'Database driver not supported: '.DB::connection()->getConfig('driver');
throw new Exception($error);
break;
}
$columns = array();
foreach(DB::select($query) as $column)
{
$columns[] = $column->$column_name;
}
if($reverse)
{
$columns = array_reverse($columns);
}
return $columns;
}
}
Use it doing:
$model = User::find(1);
dd( $model->getAllColumnsNames() );
You may try Schema::getColumnListing('tablename'):
$columns = Schema::getColumnListing('users'); // users table
dd($columns); // dump the result and die
Result would be something like this depending on your table:
array (size=12)
0 => string 'id' (length=2)
1 => string 'role_id' (length=7)
2 => string 'first_name' (length=10)
3 => string 'last_name' (length=9)
4 => string 'email' (length=5)
5 => string 'username' (length=8)
6 => string 'password' (length=8)
7 => string 'remember_token' (length=14)
8 => string 'bio' (length=3)
9 => string 'created_at' (length=10)
10 => string 'updated_at' (length=10)
11 => string 'deleted_at' (length=10)
You can dig down into DB's Doctrine instance.
$columns = DB::connection()
->getDoctrineSchemaManager()
->listTableColumns('table');
foreach($columns as $column) {
print $column->getName();
print $column->getType()->getName();
print $column->getDefault();
print $column->getLength();
}
edit: Doctrine is no longer (as of L4.1) installed by default (it's a 'suggested' rather than 'required' package), but can be added to your composer.json as doctrine/dbal to retain this functionality.
I think there's a couple different options, if you are using an Eloquent model, you can look at the getAccessibleAttributes() method, which in theory would give you all the columns of a model consider Eloquent seems them as properties.
For example, you'd be able to do something like this for your users table on a User Eloquent model.
$user = // Retrieve your User model.
$columns = User->getAccessibleAttributes();
Another Eloquent method to look at that's similar, but doesn't have the 'accessibility' requirement is the attributesToArray() method. The returned array of which should have your columns as a key. Then you can use the PHP function array_keys() to build an array of the keys, which would be your columns.
$user = // Retrieve your User model.
$columns = array_keys(User::attributesToArray());
I know it might not be the answer for everyone, but maybe you can grab one record, and get all keys of the data. Ex.
array_keys(User::first()->toArray());
If you have a Model instance you can retrieve like following:
$table_name = $model->getTable();
$connection = $model->getConnection();
$schemaBulder = $connection->getSchemaBuilder();
$columns_array = $schemaBulder->getColumnListing($table_name);
works for Laravel 5
You also can try this:
abstract class BaseModel extends Eloquent {
public function getColumnsNames()
{
$connection = DB::connection();
$connection->getSchemaBuilder();
$table = $connection->getTablePrefix() . $this->table;
$grammar = $connection->getSchemaGrammar();
$results = $connection->select($grammar->compileColumnExists(), array($connection->getDatabaseName(), $table));
return $connection->getPostProcessor()->processColumnListing($results);
}
}
I use SQL Server and the Schema way worked for me:
$columns = array_keys(Schema::getConnection()
->getDoctrineSchemaManager()
->listTableColumns($yourModel->getTable()) );

Phalcon\Mvc\Model::find() together with Phalcon\Mvc\Model\Query\Builder

I am trying to use Phalcon\Mvc\Model\Query\Builder object together with Phalcon\Mvc\Model::find() method to customize data load behaviour.
All model rows in the table have "record_status" field which is used to mark records active/inactive.
I intend to extend Model::find() and Model::findFirst() methods to always add "record_status=1" constraint to all my Model queries. But for now, I'm just trying to pass Query\Builder object on to ::find() method externally:
class User extends Phalcon\Mvc\Model
{
}
$user = new User();
/**
* #var Phalcon\Mvc\Model\Query\Builder
*/
$query = $user->getModelsManager()->createBuilder();
$query->where('email = :email:', [
'email' => 'root#yahoo.com'
])->andWhere('record_status = :status:', [
'status' => 1
])->from('users');
$found = $user->find($query);
foreach ($found as $foundUser) {
...
}
The problem is that ->find($query) returns ALL rows from the database, ignoring WHERE clauses set to $query.
When inspecting properties of $query & $user I see the following relevant protected properties:
$query::_conditions = '(email = :email:) AND (record_status = :status:)';
$query::_bindParams = array(
'email' => 'root#yahoo.com',
'status' => 1
);
$user::_count = 4; // This is wrong, this corresponds to TOTAL number of rows
$user::_result->_bindParams = NULL; // Bound parameters have disappeared
$user::_result->_sqlStatement = 'SELECT `users`.`id`, `users`.`email`, `users`.`record_status` FROM `users`'; // As you can see, there is no WHERE clause
I'm on Phalcon 1.3.0, PHP 5.5.1.
I expect find() and findFirst() methods to accept Query\Builder() object and fetch the correct records. Is this a bug or am I approaching it incorrectly?
Thanks,
Temuri
Yep you have things wrong.
The Model::find() and Model::findFirst() functions accept arrays, int or string and are wrappers for query builder.
You have at least two options:
a) use query builder directly:
// ... here is your query builder script as in question
$results = $query->getQuery()->execute();
$firstFound = $results->getFirst();
b) pass array to Model::findFirst():
$firstFound = User::findFirst(
array(
'(email = :email:) AND (record_status = :status:)',
'bind' => array('email' => 'root#yahoo.com', 'status' => 1)
)
);

Database results as objects or arrays?

This question is similar to Mysql results in PHP - arrays or objects? However, my question expands on what has been discussed there.
I'm trying to decide which format is better for working with database results: objects or arrays. I'm not concerned about performance (from what I understand it makes little difference). My focus is also more on displaying the results—not creating, updating or deleting them.
To date I've always used objects, via functions like mysqli_fetch_object or PDO's fetchObject. This normally works nice, until I start doing joins. Joins lead to strange objects that are a blend of fields from two or more tables. My code quickly starts getting confusing.
I should note, I'm assigning specific class names, and not sticking with the default stdClass. I do this so that I can access any helper methods I've created in my classes. For example:
foreach ($members as $member)
{
echo $member->full_name();
echo $member->age();
}
For the sake of clarity, I'm considering moving to arrays for all my database results. From what I've read others do this as well. However, this leaves me with no easy way to access my helper methods.
Using the above example, I guess I could just output both the first and last name instead of using the full_name() method, not a big deal. As for the age() method, I guess I could create a generic utility class and put it in there.
My questions:
If you use (model) objects, how do you deal with joins?
If you use arrays, how do you deal with helper methods?
I've always used objects - but I don't put the data in directly from the query. Using 'set' functions I create the layout and so avoid issues with joins and naming collisions. In the case of your 'full_name' example I would probably use 'as' to get the name parts, set each in the object and offer 'get_full_name' as a member fn.
If you were feeling ambitious you could add all sorts of things to 'get_age'. Set the birth date once and go wild from there.
EDIT:
There are several ways to make objects out of your data. You can predefine the class and create objects or you can create them 'on the fly'.
--> Some v simplified examples -- if this isn't sufficient I can add more.
on the fly:
$conn = DBConnection::_getSubjectsDB();
$query = "select * from studies where Status = 1";
$st = $conn->prepare( $query );
$st->execute();
$rows = $st->fetchAll();
foreach ( $rows as $row )
{
$study = (object)array();
$study->StudyId = $row[ 'StudyId' ];
$study->Name = $row[ 'StudyName' ];
$study->Investigator = $row[ 'Investigator' ];
$study->StartDate = $row[ 'StartDate' ];
$study->EndDate = $row[ 'EndDate' ];
$study->IRB = $row[ 'IRB' ];
array_push( $ret, $study );
}
predefined:
/** Single location info
*/
class Location
{
/** Name
* #var string
*/
public $Name;
/** Address
* #var string
*/
public $Address;
/** City
* #var string
*/
public $City;
/** State
* #var string
*/
public $State;
/** Zip
* #var string
*/
public $Zip;
/** getMailing
* Get a 'mailing label' style output
*/
function getMailing()
{
return $Name . "\n" . $Address . "\n" . $City . "," . $State . " " . $Zip;
}
}
usage:
$conn = DBConnection::_getLocationsDB();
$query = "select * from Locations where Status = 1";
$st = $conn->prepare( $query );
$st->execute();
$rows = $st->fetchAll();
foreach ( $rows as $row )
{
$location = new Location();
$location->Name= $row[ 'Name' ];
$location->Address = $row[ 'Address ' ];
$location->City = $row[ 'City' ];
$location->State = $row[ 'State ' ];
$location->Zip = $row[ 'Zip ' ];
array_push( $ret, $location );
}
Then later you can loop over $ret and output mailing labels:
foreach( $ret as $location )
{
echo $location->getMailing();
}
It’s preference at the end of the day. Personally, I prefer objects. Although CakePHP uses arrays for results using the “object” name as the array key. However, things start to get funny when you fetch related records in CakePHP.
With your problem, you could simply have objects within objects. For example:
stdClass Object
(
[id] => 1
[title] => Article Title
[published] => 2013-03-04 16:30:00
[category] => stdClass Object
(
[id] => 1
[name] => Category Name
)
)
You can then display associated data in your views as follows:
<?php echo $article->category->name; ?>
Or if you use getters and setters:
<?php echo $article->getCategory()->getName(); ?>
There’s no right or wrong answer. As I say, it’s all personal preference.
I think its better to represent all of your datas and its type in form of Model. For both joined and singular objects. Doing so will always omit your problem.
class Member_Details {
public $id;
public $first_name;
public $last_name;
public function FullName() {
return $this -> first_name." ".$this -> last_name;
}
}
class Member_Address {
public $id;
public $address;
public $city;
}
class MemberJoins {
public $objects = array();
}
After creating such classes you can configures a JOIN in the following way.
$obj_details = new Member_Details();
$obj_address = new Member_Address();
//Add data to the objects and then
//Then create the join object
$obj_address_details = new MemberJoins();
$obj_address_details -> objects = array($obj_details, $obj_address);
These both have a common property id from which its data can be linked.
I think you are talking about weird objects coming up using SELECT on two or more tables.
I solve this by using AS in my sql to give it a more simple name.
SELECT IFNULL(SUM(table2.big_name),0) AS sumBig
...
$result=$PDO->fetchObject();
$sum=$result->sumBig;

Categories