Getting value of joined table Yii 2 - php

Hello I am trying to access a value from a joined table schead.section to store in subjectcontainer.section, mainly I am using the scstock data but the section part is located in schead.section so what I did was to join the schead and schstock together so that I can have access to the section column. Here is what I did.
$subject = ActiveCurriculum::find()
->select('scstock.*')
->leftJoin('schead', 'schead.TrNo = scstock.TrNo')
->where([ 'schead.TrNo' => $TrNo])
->one();
$activesubject = new ActiveSubject();
$activesubject->clientid = $clientid;
$activesubject->TrNo = $subject->TrNo;
$activesubject->subjectcode = $subject->subjectcode;
$activesubject->schedday = $subject->schedday;
$activesubject->schedtime = $subject->schedtime;
$activesubject->section = $subject->section;
$activesubject->room = $subject->room;
$activesubject->units = $subject->units;
$activesubject->save();
//reduces the slot of ccsubject by 1
$subject->slots = $subject->slots - 1;
//never forget the saving part
$subject->save();
First $subject will access sctock table to join will schead via TrNo. then $activesubject will access subjectcontainer table to store the values in. Now my problem is I am getting this error.
Can someone help me in trying to solve this?

Make sure to define relation to the Schead object in your model. Example of such relation:
/**
* #property $schead Schead
*/
class YourModel extends \yii\db\ActiveRecord
{
/**
* #return Schead
*/
public function getSchead()
{
return $this->hasOne(Schead::className(), ['field1' => 'field2']);
}
}
Also, $subject->schead.section is a wrong way of accessing related model attributes. Use $subject->schead->section instead. If having schead is optional, don't forget to check existence of related object first, for example:
$subject->schead ? $subject->schead->section : null
Also check code for typos (probably sched / schead?). You can read more about working with relations in official docs.

Related

How to filter on Doctrine Entity Object?

So I have a database setup like this.
Phone numbers belong to groupings. And users belong to groupings as well. I'm trying to figure out how to get all users that belong to a grouping but through the entity object instead of just a query if this is possible.
For example I'm aware I could do a query like this...
<?php
/**
* Auto generated by MySQL Workbench Schema Exporter.
* Version 3.0.3 (doctrine2-annotation) on 2017-03-27 04:09:37.
* Goto https://github.com/johmue/mysql-workbench-schema-exporter for more
* information.
*/
namespace Entity;
use Doctrine\ORM\Mapping as ORM;
use Entity\BaseGrouping;
/**
* Entity\Grouping
*
* #ORM\Entity()
*/
class Grouping extends BaseGrouping
{
public function getUsersByPriority(){
global $entityManager;
$users = $entityManager->getRepository('Entity\User')->findBy(array(),array('priority' => 'ASC'));
return $users;
}
}
With a little modification I could add another filter perhaps so that only the correct results pertaining to that group are shown instead of everything. Right now this will result in just every user showing instead of those that should belong to just the group.
What I'm looking for is something kind of like this...
$results = $entityManager->getRepository('entity\Phonenumber')->findBy(array('number' => '+'.$numberCalled));
if(count($results)<=0 || count($results)>1){
sendEmail('Error Occured', 'There was duplicate phone numbers in the database, used fallbacknumber<br/><br/>'.print_r($_REQUEST,true),"joe#poolserviceusa.com");
return $fallbacknumber;
}else{
$phonenumber = $results[0];
$group = $phonenumber->getGrouping(); //#JA - Returns the group object and stores it to variable group in scope
}
//Get list of all users in the group
$users = $group->getUsersByPriority(); //#JA - Returns all users associated with the group
//Find the first active and not busy user
foreach($users as $user){
echo '<test>'.$user->getUserName().'<test>';
}
Since I mapped correctly all the doctrine classes I'm able to just say $phonenumber->getGroupings(); and it returns me only the groupings that belong to that phonenumber which is perfect!
What I need now however is all the users that belong to that particular group?
Easy enough if we do $group->getUsers(); The problem here is I need the users sorted by priority and there is no sorting when I use these default methods.
How do I get all the users of just the group while sorting by priority?
I think I found the answer but I don't know if this is the best answer or not. I modified the function getUsersByPriority to this.
public function getUsersByPriority(){
global $entityManager;
$grouping_id = $this->getId();
$users = $entityManager->getRepository('Entity\User')->findBy(array('grouping_id' => $grouping_id),array('priority' => 'ASC'));
//#JA - Get reference to the users of just this grouping.
$users = $this->users;
return $users;
}
I didn't realize I could use $this->getId(); to get reference to the current instance in this case.

Using \Zend_Db_Table_Abstract::find($id). MySQL SET field returns string instead of (wanted) int

Basic question How can I fetch the 'type' column as integer value from inside the table mapper?
I have a PHP Zend Framework 1.12 application running a website. Inside MySQL are multiple tables with multiple columns.
Inside two tables I use the SET type. The column is named 'type' and as 'set('LOCAL','EXTERNAL')'. Don't mix up this field type with the ENUM please!
So far no problems, querying the table and fetching the type column as INT or STRING is not a problem:
$Sql = $Db->select()->from('tablename', ['type_as_int' => new \Zend_Db_Expr('type+0')]); //returns INT (if both are selected: 3)
$Sql = $Db->select()->from('tablename', ['type']); //returns STRING (if both are selected: LOCAL,EXTERNAL)
But, in this application also has table mappers that extend Zend_Db_Table_Abstract.
Inside the mapper resides the 'find()' method. Default built in into the abstract to find records by their primary key.
But.. When I use the object to fetch a record , I find the following response inside my populate method:
array([type] => LOCAL,EXTERNAL)
Querying it by hand (and defining the columns myself) would be an options ($this->select()->from...), but isn't there a more elegant way?
(I know that I am using an older version of ZF, but upgrading would cost too much time at this moment.)
After the bounty was started I noticed that there wasn't a really simple anwer, so I began looking deeper into Zend Framework 1.12 and the mapper objects that I use.
I noticed that the 'find()' method just uses the primary key columns to build a query.
So starting with that knowledge I built my own 'find()' method which resides in the 'abstract model mapper' and uses the 'find()' mapper inside the class that extends \Zend_Db_Table_Abstract
/* sample abstract mapper class with find */
abstract class MapperAbstract {
/*
* Zend db table abstract object
* #var \Zend_Db_Table_Abstract
*/
private $DbTable;
public function find($id, $Model) {
$Select = $this->$DbTable->select(\Zend_Db_Table_Abstract::SELECT_WITH_FROM_PART);
//Fetch record and populate model if we got
//a result
$Row = $this->$DbTable->fetchRow($Select);
//do some extra shizzle
if ($Row !== null) {
return $Model->populate((array)$Row);
}
return;
}
}
Now I need to add a method that overrides the default columns.
So I created a method called 'overrideColumns()' that return an array filled with column names that need to be selected or must be overriden.
/**
* Returns array with columns that need to be overridden
* or selected as extra
* #return array
*/
public function overrideColumns() {
return ['type' => new \Zend_Db_Expr('type+0')];
}
And from that point I only needed to adjust the $Select query so it would use the 'overrideColumns()' method.
So the full class becomes something like:
/* sample abstract mapper class with find */
abstract class MapperAbstract {
/*
* Zend db table abstract object
* #var \Zend_Db_Table_Abstract
*/
private $DbTable;
/**
* Returns array with columns that need to be overridden
* or selected as extra
* #return array
*/
private function overrideColumns() {
return ['type' => new \Zend_Db_Expr('type+0')];
}
public function find($id, $Model) {
$Select = $this->DbTable->select(\Zend_Db_Table_Abstract::SELECT_WITH_FROM_PART);
//Check if we need to override columns in the select query
$overrideColumns = $this->getOverrideColumns();
if (!empty($overrideColumns)) {
$Select->columns($overrideColumns); //overrides the columns
}
//Add where clause to the query
//I know there can also be a compound primary key, but
//I'm just ignoring that in this example
$Select->where($this->DbTable->getPrimaryKeyColumn() . ' = ?', $id);
//doing some extra shizzle
//that is not important when I want to explain stuff
//Fetch record and populate model if we got a result
$Row = $this->DbTable->fetchRow($Select);
if ($Row !== null) {
return $Model->populate((array)$Row);
}
return;
}
}
So.. after a while I found the answer I was looking for, without having to declare all columns.

Efficiently retrieve a PHP object from multiple MySQL tables

I have the following PHP classes:
User.php
<?php
class User {
public $id;
public $name;
}
?>
Forummessage.php
<?php
class Forummessage {
public $id;
public $user_id; // message coming from this user
public $message;
public $datetime;
// Additionally, an object should be able to get the user instances
public $user; // should be instance of User
}
?>
Of course the class properties are usually private and accessed with public setters/getters. In order to keep this example as easy as possible, I made everything public.
Furthermore, assume the following MySQL tables.
user
id name
------------
1 tester
2 anyuser
...
forummessage
id user_id message datetime
---------------------------------------------
1 1 hello... 2014-04-04 12:00:00
2 2 yoyo... 2014-04-04 12:00:10
...
What is the fastest and most performant way to get an array of Chatmessage with all properties given?
Right now, I have a PDO wrapper class with this method:
/**
* Performs a query to the database and returns the desired type
* #param string $statement the pdo query
* #param array $params the params
* #param string $returntype optional param (default: 'bool'), should be either 'bool', 'array' or a valid class name
* #return bool|array returns either a bool depending on the success of the query or an array with the resulting data
*/
function query($statement, $params = array(), $returntype = 'bool');
In case I pass a valid class name as $returntype, then this method uses $stmt->fetchAll(\PDO::FETCH_CLASS, $returntype); in order to return an array of class instances.
That is how I would do it:
// Automatically generates an array of Forummessage
$arrayOfForummessage = $wrapper->query('
SELECT
forummessage.id AS id, // NOTE: I MAKE SURE THE PROPERTIES MATCH TO THE PHP CLASS
user_id AS user_id,
message
datetime,
name AS user_name // NOTE: NOT USED YET
FROM user, forummessage
WHERE user.id = forummessage.user_id
', array(), 'Forummessage');
This works well, but as you will understand the property user is still NULL. How would you make sure that the user property is given? As you can see, the data is in the query.
Of course I could just make a for-loop into the Forummessage constructor and look for the right properties in order to fill create an instance of User and assign it to the Forummessage class property. The problem is that this is really slow when having many properties and many objects. If you have suggestions, I am curious to read more about them.

Laravel-eloquent: Call to undefined method Illuminate\Database\Eloquent\Collection::where()

I have two models in many-to-one relationship:
class Meal extends \Eloquent {
/**
* public Integer $id; - primary key
* public String $name;
*/
protected $fillable = array('id','name');
public function mealProperties()
{
return $this->hasMany('MealProperty');
}
}
class MealProperty extends \Eloquent {
/**
* public Integer $id; - primary key
* public Integer $meal_id;
*/
protected $fillable = array('id','meal_id');
public function meal()
{
return $this->belongsTo('Meal', 'meal_id');
}
}
if I ask for first meal first mealProperty everything go fine:
$mealProp = Meal::first()->mealProperties->first();
but if I ask for mealProperty with specific id of first meal this way:
$mealProp = Meal::first()->mealProperties->where('id','=','1')->first();
I get this error:
Call to undefined method Illuminate\Database\Eloquent\Collection::where()
I google what I'm doing wrong two hours, but still nothing.
If I can't use where method, what is possible way to get specific mealProperty?
Thank you for help!
UPDATE for Laravel 5:
Since v5 release there is a method where on the Support\Collection object, so this question/answer becomes irrelevant. The method works exactly like filter, ie. returns filtered collection straight away:
$mealProp = Meal::first()->mealProperties->where('id','=','1'); // filtered collection
// that said, this piece of code is perfectly valid in L5:
$mealProp = Meal::first()->mealProperties->where('id','=','1')->first();
You must distinguish Laravel behaviour:
(dynamic property) Eloquent Collection or Model
$meal->mealProperties
Relation Object
$meal->mealProperties()
Now:
// mealProperties is Eloquent Collection and you call first on the Collection here
// so basically it does not affect db query
$mealProp = Meal::first()->mealProperties->first();
// here you try to add WHERE clause while the db query is already called
$mealProp = Meal::first()->mealProperties->where('id','=','1')->first();
// So this is what you want to do:
$mealProp = Meal::first()->mealProperties()->where('id','=','1')->first();
You may try this:
$mealProop1 = Meal::first()->mealProperties->find(1); // id = 1
Or something like this:
$mealProops = Meal::first()->mealProperties;
$mealProop5 = $mealProops->find(5); // id = 5
$mealProop7 = $mealProops->find(7); // id = 7
Instead of this:
$mealProp = Meal::first()->mealProperties->where('id','=','1')->first();
Also, following should work:
$mealProp = Meal::first()->mealProperties->first();

Working with a MY_Model

I’m using jamie Rumbelow’s MY model as a way to better deal with my application.
https://github.com/jamierumbelow/codeigniter-base-model
The MY_model is the same except I have an added in variable for defining whether or not an item in the db is marked as being soft deleted or not.
protected $soft_delete_value = 3;
I only have that variable defined and have not altered his code yet to account for this value.
I have two things I want to do with this titles model that I need help understanding.
Titles Table - title_id, title_name, title_status_id
Title_Statuses_Table - title_status_id, title_status_name
What I want it to do is retrieve all of the rows that have a title_status_id of 1 and 2 and 3 because the soft delete value is different than the default set in the MY Model. What I would also like to have is instead of it returning the integer have it return the name of the status.
Expected results:
An array of objects that contain a title_id, title_name, title_status_name for which the titles have a status id of 1,2, or 3.
Testing
$titles = $this->titles_model->get_all();
echo "<pre>";
print_r($titles);
echo "</pre>";
Actual results:
SELECT *
FROM (`titles`)
WHERE `title_status_id` = 0
<pre>Array
(
)
My Code
class Titles_model extends MY_Model
{
/* --------------------------------------------------------------
* VARIABLES
* ------------------------------------------------------------ */
/**
* This model's default database table.
*/
public $_table = 'titles';
public $primary_key = 'title_id';
/**
* Support for soft deletes and this model's 'deleted' key
*/
public $soft_delete = TRUE;
public $soft_delete_key = 'title_status_id';
public $soft_delete_value = 4;
public $_temporary_with_deleted = FALSE;
public function __construct()
{
parent::__construct();
}
}
Anybody else have any additional ideas/suggestions?
EDIT:
I've been tryign to figure this out all day and have hit a dead end.
well here would be the function that you would need to get your expected result
$this->db->select('
titles.*,
status.*,
')
->join('status s', 'titles.title_status_id = s.title_status_id', 'LEFT')
->where('titles.title_status_id', 1)
->or_where('titles.title_status_id', 2)
->or_where('titles.title_status_id', 3)
->from('titles')
->get()
->result_object();

Categories