phalcon - Relationships not defined when converting resultset to array? - phalcon

I have tested it with 2 methods:
The first:
class ProjectsController extends ControllerBase
{
public function indexAction()
{
$row = array();
$projects = Projects::find();
foreach ($projects as $project) {
foreach($project->employees as $employee){
echo "Employee: " . $employee->name;
}
}
exit;
}
}
Output:
Employee: Admin
The second:
class ProjectsController extends ControllerBase
{
public function indexAction()
{
$row = array();
$projects = Projects::find();
$projects = $projects->toArray();
foreach ($projects as $project) {
foreach($project["employees"] as $employee){
echo $employee->name;
}
}
exit;
}
}
Output:
Notice: Undefined index: employees in app/controllers/ProjectsController.php on line 10
When converting the resultset to array the relationships aren't added to the array, is there a workaround to add it to the array?
The reason I converted the resultset to an array is to edit results for example calculating progress or something like that, without saving it to the database.
Things like this:
foreach($projects as &$project){
//count all the todos.
$todos = Todos::find("project_id = '".$project["id"]."'");
$numberOfTodos = $todos->count();
//count all the todos that are done.
$todos = Todos::find("project_id = '".$project["id"]."' AND status_id = 9");
$numberOfDoneTodos = $todos->count();
$project["percentageDone"] = ($numberOfDoneTodos / $numberOfTodos) * 100;
var_dump($row);exit;
}
$this->view->setVar("projects",$projects);
So I don't have to do calculations on the view side and only have to output it

Yes, when you convert a result set to an array only scalar values are converted.
But for adding a calculated property to your model there's no need to convert it to an array, you can change or create new properties as you wish and it will only be saved to the database when you call for example $project->save() and just properties that match a column name will be stored in the database.
For adding calculated properties I'd recommend you to use the event afterFetch that gets fired for each model retrieved from the database:
class Projects extends \Phalcon\Mvc\Model
{
...
public function afterFetch()
{
//Adds a calculated property when a project is retrieved from the database
$totalTodos = Todos::count("project_id = $this->id");
$completeTodos = Todos::count("project_id = $this->id AND status_id = 9");
$this->percentageDone = round(($completeTodos / $totalTodos) * 100, 2);
}
}

Related

how to like value to %field_value% in sql or codeigniter?

I have a table named uri_table that contain:
id, uri_segment
1, /dir_name/bla-bla-1/
2, /dir_name/bla-bla-2/
3, /dir_name/bla-bla-3/
I want to get the pure link that only contain until controller_name and the controller param are not included. but when I use $_SERVER['URI_SEGMENT'] it will get the controller param too.
so I can't do this code below to search in my model:
function check_uri()
{
$this->db->like('uri_segment',$uri_segment,'after');
$id = $this->db->get('uri_table')->row_array()['id'];
return $id;
}
instead of:
function check_uri($request_uri=$_SERVER['URI_SEGMENT'])
{
//trim controller param that is numeric
for($i = strlen($request_uri)-1;$i > 0;$i--)
{
if(is_numeric($request_uri[$i]) || $request_uri[$i]=='/')
{
continue;
}
else
{
$request_uri = substr($request_uri,0,$i+1);
break;
}
}
$this->db->where('uri_segment',$request_uri);
$id = $this->db->get('uri_table')->row_array()['id'];
return $id;
}
This is my code right now but is also can remove param that is number if the $request_uri = '/dir_name/bla-bla-3/1/some_param/3' it'll return $id null. What can I do to remove the param/get uri without controller param or how to compare the $uri_segment to uri_segment ($this->db->like($uri_segment, '%uri_segment%'))?
Do one thing when you create a controller in that store the controller name like this:
class About extends CI_Controller {
// MVC config
var $PANEL = '';
var $CONTROLLER = 'about';
var $MODEL = 'mdl_about';
var $TITLE = 'page title';
var $LIST_PAGE_NAME = 'aboutus';
function About() {
parent::__construct();
//$this->load->model($this->MODEL, 'model');
}
function index() {
$this->load->view($this->LIST_PAGE_NAME);
}
}
So that above controller, model, page title and view page can be use anywhere is related to that controller.
To display the variable value use like this:
echo $this->CONTROLLER;
Or you can try this:
$this->router->fetch_class(); //for controller
$this->router->fetch_method(); //for method

Phalcon query builder can't get joined table data

I have 2 table 'sanpham' and 'danhmuc'. I use phalcon query builder to get data from 2 tables.
$laytin = $this->modelsManager->createBuilder()
->from("sanpham")
->innerJoin('danhmuc','sanpham.danhmuc=danhmuc.sodanhmuc')
->where('sanpham.sosanpham = '.$id.'')
->getQuery()
->getSingleResult();
$breadcrumbs = array('/' => Tool::getTranslation()->_('trangchu'),"/Loai-san-pham/".$laytin->tendep."/".$laytin->sodanhmuc => $laytin->tendanhmuc,'' => $laytin->tieudesanpham );
The query runs, but $laytin->tendep, $laytin->sodanhmuc, $laytin->tendanhmuc in 'danhmuc' table doesn't display. Every column in 'sanpham' table (such as: $laytin->tieudesanpham) displays properly.
You can add specific columns with:
$this->modelsManager->createBuilder()->columns('danhmuc.tend‌​ep, danhmuc.sodanhmuc')
With this method you will have to add each column you want in your output. QueryBuilder docs.
Another method is to query the Sanpham model.
For example:
class Sanpham extends \Phalcon\Mvc\Model
{
public static function findSomething($something)
{
// this is your actual query, it replaces the queryBuilder
return self::query()
->where('sanpham.sosanpham = :id:', ['id' => $something])
->innerJoin('danhmuc', 'sanpham.danhmuc = danhmuc.sodanhmuc')
->execute()->getFirst();
}
public function initialize()
{
// define the relation to danhmuc
$this->belongsTo('danhmuc', 'danhmuc', 'sodanhmuc');
}
}
class Danhmuc extends \Phalcon\Mvc\Model
{
public function initialize()
{
// there are other options besides "hasMany", like "hasOne".
// this is your relation to sanpham
$this->hasMany('sodanhmuc', 'sanpham', 'danhmuc');
}
}
class YourController extends \Phalcon\Mvc\Controller
{
public function testAction()
{
// get your first record in Sanpham matching "12345"
$sanpham = Sanpham::findSomething(12345);
// from your Sanpham object, get the related danhmuc object.
// this works because we defined the relations (belongsTo and hasMany)
$danhmuc = $sanpham->getRelated('danhmuc');
// now you have access to the values of danhmuc via the $danhmuc variable
$breadcrumbs = [
'/' => Tool::getTranslation()->_('trangchu'),
"/Loai-san-pham/" . $danhmuc->tendep => $danhmuc->tendanhmuc,
'' => $danhmuc->tieudesanpham,
];
}
}
Check the Phalcon model docs for more info on this.

Edit profile page with 3 tables - Yii frameworks

I am new on Yii framework, so please i need some help where to start.
What i need is, action and module to display a form to a user, which his will be able to edit is own profile (with profile picture), so i have 3 table
user_account || user_personal || user_general
how can i build a form that insert and update those 3 table at once?
i try this:
This is what i did, but its still not saving the data even into 1 table.
public function actionUpdate() {
$model = new ProfileUpdate();
if(isset($_POST['ProfileUpdate']))
{
$model->attributes = $_POST['ProfileUpdate'];
if($model->validate())
{
$account = new Profile();
$account->userid = Yii::app()->user->id;
$account->name = $model->name;
$account->website = $model->website;
$account->category = $model->category;
$account->save();
$this->redirect('profile');
}
}
model:
class Profile extends CActiveRecord
{
public $userid;
public $name;
public $website;
public $category;
public static function model()
{
return parent::model(__CLASS__);
}
public function tableName()
{
return 'userinfo';
}
public function primaryKey()
{
return 'id';
}
public static function userExists($user)
{
return self::model()->countByAttributes( array('username'=>$user) ) > 0;
}
}
You can use all three models in a single function
for example:
In create function
$model_account = new user_account;
$model_personal= new user_personal;
$model_general = new user_general;
$this->render('create',array(
'model_account'=>$model_account, 'model_personal' => $model_personal, 'model_general' => $model_general
));
here the all three models pass by render to create page.
in form page you can use the every model attributes as fields
Like this
echo $form->textField($model_account,'account_name');
echo $form->textField($model_personal,'email');
echo $form->textField($model_general,'address');
In create function / Update function
$model_account->attributes = $_POST['user_account'];
$model_personal->attributes = $_POST['user_personal'];
$model_general->attributes = $_POST['user_general'];
if($model_account->validate() && $model_personal->validate() && $model_general->validate())
{
$model_account->save();
$model_personal->save();
$model_general->save();
}

How to extend Illuminate\Database\Query\Builder

I'm planning to have a function that will store the sql statement on the Cache using the given second parameter on remember() as the key and whenever the sql statement changes it will run against the database again and overwrite the stored sql, also the cached result, and if not it will take the default cached result by the remember() function.
So I am planning to have something like this on Illuminate\Database\Query\Builder
/**
* Execute the query based on the cached query
*
* #param array $columns
* #return array|static[]
*/
public function getCacheByQuery($columns = array('*'))
{
if ( ! is_null($this->cacheMinutes))
{
list($key, $minutes) = $this->getCacheInfo();
// if the stored sql is the same with the new one then get the cached
// if not, remove the cached query before calling the getCached
$oldSql = self::flag($key);
$newSql = $this->toSql().implode(',', $this->bindings);
if ($newSql!==$oldSql)
{
// remove the cache
\Cache::forget($key);
// update the stored sql
self::updateFlag($key, $newSql);
}
return $this->getCached($columns);
}
return $this->getFresh($columns);
}
public static function updateFlag($flag, $value)
{
$flags = \Cache::get(t().'databaseFlags', []);
$flags[$flag] = $value;
\Cache::put(t().'databaseFlags', $flags, USER_SESSION_EXPIRATION);
}
public static function flag($flag)
{
$flags = \Cache::get(t().'databaseFlags', []);
return #$flags[$flag] ?: false;
}
But the thing is, I don't want to put this directly on Illuminate\Database\Query\Builder since it is just my need for the current application I am working. I'm trying to extend Illuminate\Database\Query\Builder, but the problem is it does not detect the my extension class.
Call to undefined method Illuminate\Database\Query\Builder::getCachedByQuery()
My Extension Class
<?php namespace Lukaserat\Traits;
class QueryBuilder extends \Illuminate\Database\Query\Builder {
/**
* Execute the query based on the caced query
*
* #param array $columns
* #return array|static[]
*/
public function getCachedByQuery($columns = array('*'))
{
if ( ! is_null($this->cacheMinutes))
{
list($key, $minutes) = $this->getCacheInfo();
// if the stored sql is the same with the new one then get the cached
// if not, remove the cached query before calling the getCached
$oldSql = self::flag($key);
$newSql = $this->toSql().implode(',', $this->bindings);
if ($newSql!==$oldSql)
{
// remove the cache
\Cache::forget($key);
// update the stored sql
self::updateFlag($key, $newSql);
}
return $this->getCached($columns);
}
return $this->getFresh($columns);
}
public static function updateFlag($flag, $value)
{
$flags = \Cache::get(t().'databaseFlags', []);
$flags[$flag] = $value;
\Cache::put(t().'databaseFlags', $flags, USER_SESSION_EXPIRATION);
}
public static function flag($flag)
{
$flags = \Cache::get(t().'databaseFlags', []);
return #$flags[$flag] ?: false;
}
}
Implementing on..
<?php
use LaravelBook\Ardent\Ardent;
use Lukaserat\Traits\DataTable;
use Lukaserat\Traits\QueryBuilder as QueryBuilder;
use Illuminate\Support\MessageBag as MessageBag;
class ArdentBase extends Ardent implements InterfaceArdentBase{
use DataTable;
Am I missing something?
Is it correct that I overwrite the get() method on the Illuminate\Database\Query\Builder by renaming the function I made in my extension class from getCachedByQuery to get since I just extending the routine of the get.
I changed
public function getCachedByQuery($columns = array('*'))
to
public function get()
on my Lukaserat\Traits\QueryBuilder
and it is now working as I expected..

How do I pass SQL database query from the Model to the Controller and then the View on Code Igniter 2.0.3?

I was trying to pass SQL values from Model to Controller but the value couldn't be passed.
This the code in my model file:
class Has_alert extends CI_Model {
function __construct()
{
parent::__construct();
}
function __get_query() {
$sql = 'alerts_get_alerts';
$query = $this->db->query($sql);
$row = $query->first_row();
$header_data['hasAlert'] = $row->active;
}
}
And this is the code in my controller file:
class Chart extends CI_Controller {
// Default Constructor
public function __construct() {
parent::__construct();
$this->load->helper('html');
$this->load->model('Has_alert', '', TRUE);
$this->Has_alert->__get_query();
//$sql = 'alerts_get_alerts';
//$query = $this->db->query($sql);
//$row = $query->first_row();
//$header_data['hasAlert'] = $row->active;
}
public function index()
{
//Data Arrays
$this->load->helper('html');
$header_data['page_title'] = 'Title';
$header_data['tabid'] = "home";
//Load the headtop.php file and get values from data array
$this->load->view('includes/headertop.php', $header_data);
$this->load->view('homepage');
$this->load->view('includes/newfooter.php');
}
I got this error message on my view file:
A PHP Error was encountered
Severity: Notice
Message: Undefined variable: hasAlert
Filename: includes/headertop.php
Line Number: 184
Does anyone know what the problem is? Thank you.
Model
function __get_query() {
$sql = 'alerts_get_alerts';
$query = $this->db->query($sql);
$row = $query->first_row();
return $row->active;
}
Controller
public function index(){
$this->load->model("Has_alert");
//Data Arrays
$this->load->helper('html');
$header_data['page_title'] = 'Title';
$header_data['tabid'] = "home";
$header_data['hasAlert'] = $this->Has_alert->__get_query();
//Load the headtop.php file and get values from data array
$this->load->view('includes/headertop.php', $header_data);
$this->load->view('homepage');
$this->load->view('includes/newfooter.php');
}
I'm assuming that things like "alerts_get_alerts" is pseudocode.