count in sub-query in zend framework 2 - zend-framework2

I am new bee of Zf2, so please suggest how should I create following sql in Zend framework 2?
Select mt1.*,
(select count(mt2.parent_id)
from md_type as mt2
where mt2.parent_id = mt1.id)) as cnt
from md_type as mt1

You can try this:
$sub = new Select('md_type');
$sub->columns(array(new Expression('COUNT(mt2.parent_id) as total')))
->where(array(
new \Zend\Db\Sql\Predicate\Expression('mt2.parent_id = mt1.id')
))
;
$subquery = new \Zend\Db\Sql\Expression("({$sub->getSqlString()})");
$select = new \Zend\Db\Sql\Select('mt1');
$select->columns(array('*', 'cnt' => $subquery));
this would produce:
SELECT mt1.*,
(SELECT COUNT(mt2.parent_id) as total
FROM "md_type"
WHERE mt2.parent_id = mt1.id
) AS cnt
FROM mt1

Please try this
$sql = new Sql($this->_adapter);
$mainSelect = $sql->select()->from('mt1');
$subQry = $sql->select()
->from('md_type')
->columns(array('orderCount' => new \Zend\Db\Sql\Expression('COUNT(md_type.parent_id)')))
->where('mt2.parent_id = mt1.id');
$mainSelect->columns(
array(
'id',
'total' => new \Zend\Db\Sql\Expression('?', array($subQry)),
)
);
$statement = $sql->prepareStatementForSqlObject($mainSelect);
$comments = $statement->execute();
$resultSet = new ResultSet();
$resultSet->initialize($comments);
return $resultSet->toArray();
Reference: ZF2 - subqueries

Related

Views hook_views_query_alter JOIN

In hook_views_query_alter i build join query like this:
$join = new views_join();
$join->table = 'table_2';
$join->field = 'field_2';
$join->left_table = 'table_1';
$join->left_field = 'field_1';
$join->type = 'LEFT';
$join->extra = array(
array(
'table' => 'table_2',
'field' => 'field_3',
'value' => 'table_1.field_4',
),
);
The query should looks like this:
LEFT JOIN {table_2} table_2 ON table_1.field_1 = table_2.field_2 AND table_1.field_3 = table_2.field_4
My problem is here 'value' => 'table_1.field_4'. I can't set value as field. It treat it as string value. So at the and in my query i have unwanted single quotes.
So at the end my query looks like this:
LEFT JOIN {table_2} table_2 ON table_1.field_1 = table_2.field_2 AND table_1.field_3 = 'table_2.field_4'
I'm not sure if it's the best solution but this:
$join = new views_join();
$join->table = 'table_2';
$join->field = 'field_2';
$join->left_table = 'table_1';
$join->left_field = 'field_1';
$join->type = 'LEFT';
$join->extra = 'table_1.field_3 = table_2.field_4';
works for me.

How to get value from custom profile field in moodle in code?

How to get value from custom profile field in moodle?
i want to include the profile field in user.php
If you want to load all the user profile fields, then you can start with a user object
$user = $DB->get_record('user', array('id' => $userid));
and then call
profile_load_custom_fields($user);
to fill in the $user->profile with an array of all the custom fields.
Alternatively, you can get the contents of a single profile field via:
$sql = "SELECT ud.data
FROM {user_info_data} ud
JOIN {user_info_field} uf ON uf.id = ud.fieldid
WHERE ud.userid = :userid AND uf.shortname = :fieldname";
$params = array('userid' => $userid, 'fieldname' => 'NameOfCustomField');
$fieldvalue = $DB->get_field_sql($sql, $params);
Note this code is written off the top of my head and untested, so it may have some typos in it.
You can use:
$Data = $USER->profile['YourCustomField'];
I finally made it!!!
$sql = 'SELECT DISTINCT u.id AS userid, u.username, uif.shortname, uid.data FROM prefix_user u JOIN prefix_user_info_data as uid on uid.userid = u.id JOIN prefix_user_info_field as uif on uid.fieldid = uif.id JOIN prefix_user_enrolments ue ON ue.userid = u.id JOIN prefix_enrol e
ON e.id = ue.enrolid JOIN prefix_role_assignments ra ON ra.userid = u.id JOIN prefix_context ct ON ct.id = ra.contextid AND
ct.contextlevel = 50 JOIN prefix_course c ON c.id = ct.instanceid AND e.courseid = c.id JOIN prefix_role r ON r.id = ra.roleid
where uif.shortname = \'fieldname\' and u.id ='.$userid;
$records = $DB->get_recordset_sql($sql, array(), $params=null, $limitfrom=0, $limitnum=0);
foreach($records as $record){
$user['fieldname'] = $record->data;
}
custom fields are stored in 'user_info_field' table and data for each field and user are stored in 'user_info_data' table then you should know your fieldid in database and select data based on this id:
$field = $DB->get_record('user_info_field', array('shortname' => 'customfieldshortname'));
$fieldvalues = $DB->get_records('user_info_data',array('fieldid' => $field->id));
i hope my solutions help anybody:
need this lib
require_once($CFG->dirroot.'/user/profile/lib.php');
and now you can use:
profile_load_data($USER);
$USER->profile_field_%your_field_name%
example $USER->profile_field_HaveAnotherGradeBook;

Zend Framework2 how to make Concat and Left Join

Does not work:
$sql = new Sql($this->adapter);
$select = $sql->select();
$select->from('request')
->columns(array('*', new Expression("CONCAT(up1.value,' ',up2.value) as display_name")))
->join(array('up1'=>'user_profile'), "up1.user_id = request.request_user_id AND up1.key = 'user_first_name'", array('up1.value'), 'left')
->join(array('up2'=>'user_profile'), "up2.user_id = request.request_user_id AND up2.key = 'user_last_name'", array('up2.value'), 'left')
;
return $select;
How to make the right?
You specified fields for both joins:
->join(array('up1'=>'user_profile'), "up1.user_id = request.request_user_id AND up1.key = 'user_first_name'", array('up1.value'), 'left')
->join(array('up2'=>'user_profile'), "up2.user_id = request.request_user_id AND up2.key = 'user_last_name'", array('up2.value'), 'left')
When query is converted to actual sql, these fields will be automatically namespaced, so you will get "up1.up1.value" in fields list.
Remove fields references from joins and it should work.
UPD. Right, there's more to it. You can't pass 'user_first_name' as a string value to the "on" parameter of join as it will be interpreted as a column name. So you have to pass an expression:
$select = $sql->select();
$select->from('request')
->columns(array('*', new Expression('CONCAT(up1.value,"#",up2.value) as display_name')));
$expressionString = '? = ? AND ? = ?';
$types = array(Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE);
$parameters = array('request.user_id', 'up1.user_id', 'up1.key', 'first_name');
$expression1 = new Expression($expressionString, $parameters, $types);
$parameters = array('request.user_id', 'up2.user_id', 'up2.key', 'last_name');
$expression2 = new Expression($expressionString, $parameters, $types);
$select->join(array('up1'=>'user_profile'), $expression1, array('value'), 'left')
->join(array('up2'=>'user_profile'), $expression2, array('value'), 'left');
Y tri to:
$select = $sql->select();
$select->from('request')
->columns(array('*', new Expression('CONCAT(up1.value,"#",up2.value) as display_user_name')));
$expressionString = '? = ? AND ? = ?';
$types = array(Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER, Expression::TYPE_VALUE);
$parameters1 = array('request.user_id', 'up1.user_id', 'up1.key', 'user_first_name');
$expression1 = new Expression($expressionString, $parameters1, $types);
$parameters2 = array('request.user_id', 'up2.user_id', 'up2.key', 'user_last_name');
$expression2 = new Expression($expressionString, $parameters2, $types);
$select->join(array('up1'=>'user_profile'), $expression1, array('value'), 'left')
->join(array('up2'=>'user_profile'), $expression2, array('value'), 'left');
does not work, where the error

How to use multiple on clause in joining in zend framework 2

I am doing like this sql into zend framework sql pattern.
SELECT
jobs . *,
c.id AS cid,
c.name AS name,
c.companyImage AS companyImage,
c.logo AS logo,
count(app.userId) AS t_app,
app.applyStatus AS applyStatus,
app.userId AS appUserId
FROM
jobs
LEFT JOIN
companies AS c ON jobs.companyName = c.id
LEFT JOIN
applicants AS app ON jobs.id = app.jobId AND app.applyStatus = 1
WHERE
jobs.ownerId = 16 AND jobs.draftId != 0
GROUP BY jobs.id
ORDER BY jobs.id DESC
LIMIT 3
For this sql I already write this code for zend framework 2
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('jobs')
->join(array('c' => 'companies'), 'jobs.companyName = c.id', array('cid' => 'id', 'name', 'companyImage', 'logo'), 'left')
->join(array('app' => 'applicants'), ' jobs.id = app.jobId AND app.applyStatus = 1', array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left')
->where("jobs.ownerId ={$userId} AND jobs.draftId != 0")
->group('jobs.id')
->order('jobs.id DESC')
->limit(3);
$statement = $sql->getSqlStringForSqlObject($select);
$results = $adapter->query($statement, $adapter::QUERY_MODE_EXECUTE);
but does not work properly and its give a message like below.
SQLSTATE[42S22]: Column not found: 1054 Unknown column '1' in 'on clause'
The issue is this part:
app.applyStatus = 1
The framework is escaping 1 as if it were a column name, 1.
You need to enclose this part in an Expression too
new Expression('jobs.id = app.jobId AND app.applyStatus = 1')
I think the use of Expressions in the 'ON' parameter of the join method may depend on the version of ZF2 you are using, I think it was added 2.1+
Building on this answer. If you also want your table & column identifiers to be escaped, use this syntax:
use Zend\Db\Sql\Expression;
...
$onExpression = new Expression('? = ? AND ? = ?',
['jobs.id', 'app.jobId', 'app.applyStatus', 1],
[Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER,
Expression::TYPE_IDENTIFIER, Expression::TYPE_LITERAL]
);
$select->from('jobs')
->join(array('app' => 'applicants'), $onExpression, array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left');
The Expression constructor accepts the string, then arguments, then argument types.
public function __construct($expression = '', $parameters = null, array $types = [])
This will create a security issue. Zf2 changes your query to this:
Select * from tableA inner join tableB
on `tableA`.`column` = `tableB`.`column`
AND `tableB`.`column` = `1`
It adds
`
to each part for security issues! By using new Expression you are bypassing it and if you get applyStatus from user entry, get sure about its filtering!

How to add Sql\Expression in front of column Name in ZF2?

How to get Sql like this :
select * from foo where LOWER(foo_name) = 'test';
what i get is if Sql\Expression in right, not in left.
You can user code snippet like that.
$where = new Where();
$sql = new Sql($adapter);
$select = $sql->select();
$where->addPredicate(new Predicate\Expression('LOWER(foo_name) = ?', 'test' ));
$select->from('foo')->where($where);
However I dont think Sql\Expression on right side is possible on Zend Framework 2.
You can do it like this:
$sql = new SQL($adaptor);
$select = $sql->select()->from(array('f'=>'foo'));
$select = $select->where('foo_name' => new \Zend\Db\Sql\Expression("LOWER('test')"));
Above query would return as:
SELECT `f`.* FROM `foo` AS `f` WHERE `foo_name` = LOWER('test');
For others out looking for similar, there are actually quite a few different ways to achieve this as of ZF 2.2
Chaining (same as the accepted answer)
<?php
$sql = new Sql($adapter);
$select = $sql->select();
$select->from( array( 'f' => 'foo' ) )
->where
->addPredicate( new Predicate\Expression( 'LOWER(f.foo_name) = ?', 'test' ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = :where1
//:where1 = 'test'
?>
Note the absence of the execution command "()" of Select::$where allowing you to continue the method chaining.
Select::$where has a __get Magic method catch which returns the protected Select::$_where property within the Select object which is an instance of Sql\Where.
Predicate\Literal 1
<?php
$select->where( "LOWER(f.foo_name) = 'test'" );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>
Predicate\Literal 2
<?php
$select->where( array( "LOWER(f.foo_name) = 'test'" ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>
The two above automatically create a Predicate\Literal object for you if the indexed value (column identifier) of the array or argument supplied to the Select::where method is a string.
Predicate\Expression (manual)
<?php
$select->where( new Predicate\Expression( "LOWER(f.foo_name) = 'test'" ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>

Resources