Yii2 using ActiveQuery that uses sub-query on same Model - mysql

I have a Comments table that have parent_id foreign key that points to itself to enable threaded comment.
Comments
id INT UNSIGNED NOT NULL
parent_id INT UNSIGNED NULL
comment TEXT NOT NULL
created_time DATETIME NOT NULL
The original ActiveQuery is like this
class CommentActiveQuery extends \yii\db\ActiveQuery {
public function andWhereIsNotRemoved() {
return $this->andWhere(['isRemoved' => Comment::STATUS_IS_NOT_REMOVED]);
}
public function andWhereParentIdIs($parentId) {
return $this->andWhere(['parentId' => $parentId]);
}
public function orderByNewestCreatedTime() {
return $this->orderBy(['createdTime' => SORT_DESC]);
}
}
Now I want to sort the comments by the newest active reply.
The query is basically like this
SELECT `*`, `last_reply_time`
FROM `Comments`
WHERE `parent_id` IS NULL
ORDER BY `last_reply_time` DESC;
I'm thinking the last_reply_time is a subquery
SELECT MAX(created_time)
FROM `Comments`
WHERE `parent_id` = :something
How to build this using the CommentActiveQuery above. The farthest I can get is like this
public function orderByNewestActiveChildCreatedTime() {
return $this->addSelect([
'last_reply_time' => $subQuery
])->orderBy(['last_reply_time' => SORT_DESC]);
}
With what should I replace the $subQuery variable above? Or is there a better way?

$subQuery = new \yii\db\Query();
$subQuery->select(["max(subQ.created_time)"]);
$subQuery-> from('comments subQ');
$subQuery->where([
'parent_id' => $parentId
]);
$query = new \yii\db\Query();
$query->select([
'C.*',
$subQuery
]);
$query->from('Comments C');
$query->andWhere(
'parent_id is Null'
);
$command = $query->createCommand();
/*
Printing the command will result following sql with $parentId = 1
SELECT
`C`.*, (
SELECT
max(subQ.created_time)
FROM
`comments` `subQ`
WHERE
`parent_id` =: qp0
) AS `1`
FROM
`Comments` `C`
WHERE
parent_id IS NULL
*/
print_r($command->sql);
I am not sure about ORDER BY last_reply_time DESC; Assuming last_reply_time is db table attribute and is different from the subquery. You can simply add orderBy in the query by doing $query->orderBy('last_reply_time DESC')
I hope this would be helpful to you.Cheers :)

Related

how can i get mysql to return an array that is inside JSON

im trying to return a product that can have three images per product.
something like this:
{
product_id: 1,
product_name:"test",
category_id_fk: 1,
product_price: 12,
product_desc:"lorem-ipsum",
product_images:[path1, path2, path3]
}
Here is what i have got so far,
create table product(
product_id serial not null primary key,
category_id_fk int not null references category(category_id) ,
product_image_fk int not null references product_images(product_images_id),
product_name varchar(50) not null,
product_price int not null,
product_desc varchar(200) not null);
create table product_images(
product_images_id serial not null primary key,
product_image_one varchar(150) not null,
product_image_two varchar(150) not null,
product_image_three varchar(150) not null);
this is the query im using for the product details page
SELECT * FROM product WHERE category_id_fk = ? AND product_id = ?;
Im new to SQL and have been really having a tough time with this specifically, would
appreciate it a lot if anyone could explain to me what im doing wrong or if you have any tips for me.
I don't know what programming language you are using, but in this case I assume you are using a programming language like PHP as a REST API provider because you are using prepared statements
Here is the query:
SELECT * FROM `product_images` `pi` LEFT JOIN `product` `p`
ON `pi`.`product_images_id` = `p`.`product_image_fk` WHERE
`p`.`product_id` = ? AND `p`.`category_id_fk` = ?
Then on your PHP scripts you can make it like this:
$sql = "SELECT * FROM `product_images` `pi` LEFT JOIN `product` `p`
ON `pi`.`product_images_id` = `p`.`product_image_fk` WHERE
`p`.`product_id` = ? AND `p`.`category_id_fk` = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $productId, $categoryId);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$jsonArray = [
"product_id" => $row["product_id"],
"product_name" => $row["product_name"],
"category_id_fk" => $row["category_id_fk"],
"product_price" => $row["product_price"],
"product_desc" => $row["product_desc"],
"product_images" => [$row["product_image_one"], $row["product_image_two"], $row["product_image_three"]]
];
$expectedJson = json_encode($jsonArray);
And you can do whatever you want to the json maybe by storing it on the json file or to print it as http response
SELECT JSON_OBJECT( 'product_id', p.product_id,
'product_name', p.product_name,
'category_id_fk', p.category_id_fk,
'product_price', p.product_price,
'product_desc', p.product_desc,
'product_images', JSON_ARRAY(pi.product_image_one,
pi.product_image_two,
pi.product_image_three) ) output
FROM product p
JOIN product_images pi ON p.product_image_fk = pi.product_images_id;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=16f3a1fe3619c6c3601983d4c00de07d

Storing 2 same id of post table with different language into database

I'm building a multi language website. In this case just 2 languages, it's Indonesian and English using Laravel.
I have posts table, it will store id of each post and post_translations table is to store local, title, and description of post.
I got the problem when storing data into database. I don't have any idea how to store post without inc the id except I've added 2 same post with Indonesian and English.
This is the result (wrong)
posts table
id
1
2
post_translations table
id post_id locale title
1 1 en fisrt post
2 2 id post yang pertama
Expexted result
posts table
id
1
post_translations table
id post_id locale title
1 1 en fisrt post
2 1 id post yang pertama
PostController
public function store(Request $request) {
$this->validate($request, [
'title' => 'required',
'slug' => 'required',
'content' => 'required'
]);
$post = new Post;
$post->title = $request->title;
$post->slug = $request->slug;
$post->content = $request->content;
$post->save();
return redirect()->route('post.index');
}
Ok, so here we go (please note that this is not the only way):
install spatie/laravel-translatable with
composer require spatie/laravel-translatable
**Note: for native spatie/laravel-translatable go to version 2 **
create a table with this structure:
CREATE TABLE articles (
id int(10) UNSIGNED NOT NULL,
title text COLLATE utf8_unicode_ci,
slug text COLLATE utf8_unicode_ci,
content text COLLATE utf8_unicode_ci,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Note: beter use a migration. I just exported a table I did earlier to test
Insert the data in the datatabase in json format like this:
INSERT INTO `pages` (`id`, `title`, `slug`, `content`, `created_at`, `updated_at`) VALUES
(1, '{"ro":"Acas\\u0103","en":"Home"}', NULL, '{"ro":"<p><strong>Test title<\\/strong><\\/p>\\r\\n\\r\\n<p>Test content romanian<\\/p>\\r\\n","en":"<p><strong>test title english<\\/strong><\\/p>\\r\\n\\r\\n<p>test content english.<\\/p>\\r\\n"}', '2017-04-03 11:45:56', '2017-04-03 12:15:16');
Now create the blade to edit, update, create show etc. To get the language do something like this in the blade:
{{ $data->title }}
{!! nl2br($data->content) !!}
And in the controller:
add something like this:
/**
* Generate the field by language
*
* #param Model $entry the item selected from the database
*
* #return array
*/
public function getTranslatableFields($fields)
{
$inputs = [];
$languages = $this->getLanguages();
foreach ($languages as $language) {
foreach ($fields as $field) {
$inputs[] = [
'name' => "{$field['name']}[{$language->abbr}]",
'label' => $field['label'] . " ($language->abbr)",
'lang' => $language->abbr,
'type' => array_key_exists('type', $field) ? $field['type'] : 'text'
];
}
}
return $inputs;
}
I added this function in a LangTrait. Since I also use backpack for laravel I did some more things.
For edit I added this method in the trait:
/**
* Show the form for editing the specified resource.
*
* #param int $id the item's identifier
*
* #return Response
*/
public function edit($id)
{
$data['entry'] = Model::find($id);
$data['title'] = trans('lang_file.edit').' '.$this->entity_name; // name of the page
$data['fields'] = $this->getMultiLangFields($data['entry']);
$data['id'] = $id;
return view('crud::edit', $data);
}
/**
* Generate the field by language
*
* #param Model $entry the item selected from the database
*
* #return array
*/
protected function getMultiLangFields($entry)
{
$fields['id'] = ['name' => 'id', 'type' => 'hidden', 'value' => $entry->id];
foreach ($this->crud->update_fields as $key => $field) {
$value = null;
if (array_key_exists('lang', $field)) {
$name = preg_replace('/(\[\w{2}\])$/i', '', $field['name']);
$value = $entry->getTranslation($name, $field['lang']);
}
$fields[$key] = array_merge($field, ['value' => $value]);
}
return $fields;
}
/**
* Get the application active languages
*
* #return \Backpack\LangFileManager\app\Models\Language
*/
protected function getLanguages()
{
return Language::whereActive(1)->orderBy('default', 'desc')->get();
}
Finally in my main controller I did:
use LangTrait; (contains everything above)
In construct I added this:
$this->getTranslatableFields($fields)
where $fields it's the list of fields I need
All methods should be adapted to you html format. As I said I use backpack for laravel and fields are formatted accordingly
And finally for the getLanguage file to work I created a new table and a model in the DB:
Model:
class Language extends Model
{
protected $table = 'languages';
protected $fillable = ['name', 'flag', 'abbr', 'native', 'active', 'default'];
public $timestamps = false;
public static function getActiveLanguagesArray()
{
$active_languages = self::where('active', 1)->get()->toArray();
$localizable_languages_array = [];
if (count($active_languages)) {
foreach ($active_languages as $key => $lang) {
$localizable_languages_array[$lang['abbr']] = $lang;
}
return $localizable_languages_array;
}
return config('laravellocalization.supportedLocales');
}
public static function findByAbbr($abbr = false)
{
return self::where('abbr', $abbr)->first();
}
}
Table:
CREATE TABLE `languages` (
`id` int(10) UNSIGNED NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`app_name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`flag` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`abbr` varchar(3) COLLATE utf8_unicode_ci NOT NULL,
`script` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`native` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`active` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
`default` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Data in the table:
INSERT INTO `languages` (`id`, `name`, `app_name`, `flag`, `abbr`, `script`, `native`, `active`, `default`, `created_at`, `updated_at`, `deleted_at`) VALUES
(1, 'English', 'english', '', 'en', 'Latn', 'English', 1, 0, NULL, NULL, NULL),
(2, 'Romanian', 'romanian', '', 'ro', 'Latn', 'română', 1, 1, NULL, NULL, NULL);
Since I did this through a package I kind of messed around a little bit with the code.
Now, for the spatie/laravel-translatable package version:
set up the service provider in config/app.php add this in the providers array:
Spatie\Translatable\TranslatableServiceProvider::class,
In the model Articles add use HasTranslations; like this:
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class NewsItem extends Model
{
use HasTranslations;
public $translatable = ['name']; // list the columns you want to be translatable (will have json format)
}
save a new entry and use it:
$article = new Article;
$article->setTranslation('name', 'en', 'Updated name in English')
->setTranslation('name', 'nl', 'Naam in het Nederlands');
$article->save();
$article->name; // Returns 'Name in English' given that the current app locale is 'en'
$article->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands'
app()->setLocale('nl');
$article->name; // Returns 'Naam in het Nederlands'
examples from: https://github.com/spatie/laravel-translatable
Database table format is as stated above in the first version
If it does not work out let me know and I'll look at your code.
I think you should change your tables strucuture:
posts : id, slug.
post_translations : id, post_id, locale, title, content
Also add relation to your Post model:
public function translations()
{
return $this->hasMany(PostTranslation::class, 'post_id');
}
And update your controller:
$post = new Post;
$post->slug = $request->slug;
$post->save();
$post->translations()->create([
'locale' => 'en', //or grab it from $request
'title' => $request->title,
'content' => $request->content
])
It will create your post and add translation to it

how to get last insert id after insert query in codeigniter active record

I have an insert query (active record style) used to insert the form fields into a MySQL table. I want to get the last auto-incremented id for the insert operation as the return value of my query but I have some problems with it.
Inside the controller:
function add_post(){
$post_data = array(
'id' => '',
'user_id' => '11330',
'content' => $this->input->post('poster_textarea'),
'date_time' => date("Y-m-d H:i:s"),
'status' => '1'
);
return $this->blog_model->add_post($post_data);
}
And inside model:
function add_post($post_data){
$this->db->trans_start();
$this->db->insert('posts',$post_data);
$this->db->trans_complete();
return $this->db->insert_id();
}
I get nothing as the return of the add_post in model
Try this
function add_post($post_data){
$this->db->insert('posts', $post_data);
$insert_id = $this->db->insert_id();
return $insert_id;
}
In case of multiple inserts you could use
$this->db->trans_start();
$this->db->trans_complete();
A transaction isn't needed here, this should suffice:
function add_post($post_data) {
$this->db->insert('posts',$post_data);
return $this->db->insert_id();
}
$id = $this->db->insert_id();
From the documentation:
$this->db->insert_id()
The insert ID number when performing database inserts.
Therefore, you could use something like this:
$lastid = $this->db->insert_id();
Using the mysqli PHP driver, you can't get the insert_id after you commit.
The real solution is this:
function add_post($post_data){
$this->db->trans_begin();
$this->db->insert('posts',$post_data);
$item_id = $this->db->insert_id();
if( $this->db->trans_status() === FALSE )
{
$this->db->trans_rollback();
return( 0 );
}
else
{
$this->db->trans_commit();
return( $item_id );
}
}
Source for code structure: https://codeigniter.com/user_guide/database/transactions.html#running-transactions-manually
It is worth saying that the other answers relate to Codeigniter version 3. The answer in Version 4 (found https://codeigniter.com/user_guide/database/helpers.html) is to use $this->db->insertID()
because you have initiated the Transaction over the data insertion so,
The first check the transaction completed or not. once you start the transaction, it should be committed or rollback according to the status of the transaction;
function add_post($post_data){
$this->db->trans_begin()
$this->db->insert('posts',$post_data);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE){
$this->db->trans_rollback();
return 0;
}else{
$this->db->trans_commit();
return $this->db->insert_id();
}
}``
in the above, we have committed the data on the successful transaction even you get the timestamp
Just to complete this topic:
If you set up your table with primary key and auto increment you can omit the process of manually incrementing the id.
Check out this example
if (!$CI->db->table_exists(db_prefix() . 'my_table_name')) {
$CI->db->query('CREATE TABLE `' . db_prefix() . "my_table_name` (
`serviceid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`hash` varchar(32) NOT NULL,
`url` varchar(120) NOT NULL,
`datecreated` datetime NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=" . $CI->db->char_set . ';');
Now you can insert rows
$this->db->insert(db_prefix(). 'my_table_name', [
'name' => $data['name'],
'hash' => app_generate_hash(),
'url' => $data['url'],
'datecreated' => date('Y-m-d H:i:s'),
'active' => $data['active']
]);
**Inside Model**
function add_info($data){
$this->db->insert('tbl_user_info',$data);
$last_id = $this->db->insert_id();
return $last_id;
}
**Inside Controller**
public function save_user_record() {
$insertId = $this->welcome_model->save_user_info($data);
echo $insertId->id;
}
You must use $lastId = $this->db->insert_id();

Query 2 tables with one field linked to 2 different values

I'm trying to make a SQL query and I have some problems with it.
CREATE table entries (
id_entry INT PRIMARY KEY,
);
CREATE table entry_date (
entry_date_id INT PRIMARY KEY,
entry_id INT,
entry_price INT,
entry_date TEXT,
);
for each entry, there is several dates.
I'd like to select the entries.entry_id where that entry have, for example, the dates '23/03/2013' and '24/03/2013' linked to it.
The two dates are stored into an array:
$data = array('ci' => '23/03/2013', 'co' => '24/03/2013');
I store the dates in text for practical purpose in my treatment.
I use Zend_Db so my query is constructed like that:
$select = $table->select ()->from ( 'entries' )->setIntegrityCheck ( false );
if ($data ['ci'] != NULL) {
$select->join ( array (
'entry_dates' => 'entry_dates'
), 'entries.id_entry = entry_dates.entry_id' );
$select->where ( 'entry_dates.entry_date = ?', $data ['ci'] );
}
if ($data ['co']) {
if ($data['ci'] == NULL) {
$select->join ( array (
'entry_dates' => 'entry_dates'
), 'entries.id_entry = entry_dates.entry_id' );}
$select->where ( 'entry_dates.entry_date = ?', $data ['co'] );
}
which gives :
SELECT `entries`.*, `entry_date`.*
FROM `entries`
INNER JOIN `entry_dates`
ON entries.id_entry = entry_dates.entry_id
WHERE (entry_dates.entry_date = '23/03/2013')
AND (entry_dates.entry_date = '24/03/2013')
And, well ... It doesn't work.
When I fetch my $select, I get nothing.
I guess I miss something in my request when I do the WHERE ... AND , what should I do to get the correct output ? The real request being really long, I'd like to avoid another long subselect if possible.
It can be done in two way, either with a self-join on the entry_date table:
SELECT `entries`.entry_id
FROM `entries`
INNER JOIN `entry_dates` AS ed1
ON entries.id_entry = ed1.entry_id
INNER JOIN `entry_dates` AS ed2
ON entries.id_entry = ed2.entry_id
WHERE ed1.entry_date = '23/03/2013'
AND ed2.entry_date = '24/03/2013'
Or with an aggregate
SELECT `entries`.entry_id
FROM `entries`
INNER JOIN `entry_dates` AS ed
WHERE ed.entry_date = '23/03/2013'
OR ed2.entry_date = '24/03/2013'
GROUP BY `entries`.entry_id
HAVING COUNT(DISTINCT ed.entry_date)=2

LEFT JOIN in ZF2 using TableGateway

I have a table:
*CREATE TABLE IF NOT EXISTS `blogs_settings` (
`blog_id` int(11) NOT NULL AUTO_INCREMENT,
`owner_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`meta_description` text NOT NULL,
`meta_keywords` text NOT NULL,
`theme` varchar(25) NOT NULL DEFAULT 'default',
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`date_created` int(11) NOT NULL,
PRIMARY KEY (`blog_id`),
KEY `owner_id` (`owner_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;*
And the second table:
*CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(128) NOT NULL,
`sex` tinyint(1) NOT NULL,
`birthday` date NOT NULL,
`avatar_id` int(11) DEFAULT NULL,
`user_level` tinyint(1) NOT NULL DEFAULT '1',
`date_registered` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '0',
`is_banned` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`),
KEY `is_active` (`is_active`),
KEY `user_level` (`user_level`),
KEY `is_banned` (`is_banned`),
KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;*
How may I select all the fields from blogs_settings table and join only the 'username' field from the users table using TableGateway in ZF2, on blogs_settings.owner_id = users.user_id. Thanks in advance. Your help is much appreciated.
EDIT:
namespace Object\Model;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
class BlogsSettingsTable {
protected $tableGateway;
protected $select;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
$this->select = new Select();
}
public function getBlogs($field = '', $value = '') {
$resultSet = $this->tableGateway->select(function(Select $select) {
$select->join('users', 'blogs_settings.owner_id = users.user_id', array('username'));
});
return $resultSet;
}
public function getBlog($blogID) {
$id = (int) $blogID;
$rowset = $this->tableGateway->select(array('blog_id' => $id));
$row = $rowset->current();
if (!$row) {
throw new Exception('Could not find row with ID = ' . $id);
}
return $row;
}
public function addBlog(BlogsSettings $blog) {
$data = array(
'owner_id' => $blog->owner_id,
'title' => $blog->title,
'meta_description' => $blog->meta_description,
'meta_keywords' => $blog->meta_keywords,
'theme' => $blog->theme,
'is_active' => $blog->is_active,
'date_created' => $blog->date_created,
);
$this->tableGateway->insert($data);
}
public function deleteBlog($blogID) {
return $this->tableGateway->delete(array('blog_id' => $blogID));
}
}
With this, it executes the following query:
SELECT blogs_settings.*, users.username AS username FROM blogs_settings INNER JOIN users ON blogs_settings.owner_id = users.user_id
but the resultSet does not contain the username field from the joined 'users' table. However, when I run the query in phpmyadmin, everything is okay and I have the 'username' field from the 'users' table joined. What's the problem?
EDIT 2
ok, I now tried the following:
public function getBlogs() {
$select = $this->tableGateway->getSql()->select();
$select->columns(array('blog_id', 'interest_id', 'owner_id', 'title', 'date_created'));
$select->join('users', 'users.user_id = blogs_settings.owner_id', array('username'), 'left');
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
}
the executed query is:
SELECT `blogs_settings`.`blog_id` AS `blog_id`, `blogs_settings`.`interest_id` AS `interest_id`, `blogs_settings`.`owner_id` AS `owner_id`, `blogs_settings`.`title` AS `title`, `blogs_settings`.`date_created` AS `date_created`, `users`.`username` AS `username` FROM `blogs_settings` LEFT JOIN `users` ON `users`.`user_id` = `blogs_settings`.`owner_id`
When I run it into phpmyadmin, it joins the username field from the users table. When in zf2, it doesn't.
Here's the dump of the whole object:
Zend\Db\ResultSet\ResultSet Object
(
[allowedReturnTypes:protected] => Array
(
[0] => arrayobject
[1] => array
)
[arrayObjectPrototype:protected] => Object\Model\BlogsSettings Object
(
[blog_id] =>
[interest_id] =>
[owner_id] =>
[title] =>
[meta_description] =>
[meta_keywords] =>
[theme] =>
[is_active] =>
[date_created] =>
)
[returnType:protected] => arrayobject
[buffer:protected] =>
[count:protected] => 1
[dataSource:protected] => Zend\Db\Adapter\Driver\Pdo\Result Object
(
[statementMode:protected] => forward
[resource:protected] => PDOStatement Object
(
[queryString] => SELECT `blogs_settings`.`blog_id` AS `blog_id`, `blogs_settings`.`interest_id` AS `interest_id`, `blogs_settings`.`owner_id` AS `owner_id`, `blogs_settings`.`title` AS `title`, `blogs_settings`.`date_created` AS `date_created`, `users`.`username` AS `username` FROM `blogs_settings` LEFT JOIN `users` ON `users`.`user_id` = `blogs_settings`.`owner_id`
)
[options:protected] =>
[currentComplete:protected] =>
[currentData:protected] =>
[position:protected] => -1
[generatedValue:protected] => 0
[rowCount:protected] => 1
)
[fieldCount:protected] => 6
[position:protected] =>
)
Up... any ideas?
Adding to #samsonasik's answer and addressing the issues in its comments. You won't be able to get the joined values out of what is returned from that statement. That statement returns the model object which won't have the joined rows. You'll need to execute it as SQL at a level which will prepare it as raw SQL and return you each resulting row as an array rather than an object:
$sqlSelect = $this->tableGateway->getSql()->select();
$sqlSelect->columns(array('column_name_yourtable'));
$sqlSelect->join('othertable', 'othertable.id = yourtable.id', array('column_name_othertable'), 'left');
$statement = $this->tableGateway->getSql()->prepareStatementForSqlObject($sqlSelect);
$resultSet = $statement->execute();
return $resultSet;
//then in your controller or view:
foreach($resultSet as $row){
print_r($row['column_name_yourtable']);
print_r($row['column_name_othertable']);
}
if you're using TableGateway, you can select join like this
$sqlSelect = $this->tableGateway->getSql()->select();
$sqlSelect->columns(array('column_name'));
$sqlSelect->join('othertable', 'othertable.id = yourtable.id', array(), 'left');
$resultSet = $this->tableGateway->selectWith($sqlSelect);
return $resultSet;
You have to include username field in the BlogsSetting Model that is used as model from BlogsSettingTable (The TableGateway)
class BlogsSetting {
public $blog_id;
public $interest_id;
public $owner_id;
public $title;
public $meta_description;
public $meta_keywords;
public $theme;
public $is_active;
public $date_created;
public $username;
public function exchangeArray($data)
{
// Create exchangeArray
}
}
Hope this helps
This is the exact need for both Join and Where clauses with tableGateway.
public function getEmployeefunctionDetails($empFunctionId) {
$empFunctionId = ( int ) $empFunctionId;
//echo '<pre>'; print_r($this->tableGateway->getTable()); exit;
$where = new Where();
$where->equalTo('FUNCTION_ID', $empFunctionId);
$sqlSelect = $this->tableGateway->getSql()->select()->where($where);
$sqlSelect->columns(array('FUNCTION_ID'));
$sqlSelect->join('DEPARTMENTS', 'DEPARTMENTS.DEPARTMENT_ID = EMPLOYEE_FUNCTIONS.DEPARTMENT_ID', array('DEPARTMENT_ID','DEPARTMENT_NAME'), 'inner');
$sqlSelect->join('ROLES', 'ROLES.ROLE_ID = EMPLOYEE_FUNCTIONS.ROLE_ID', array('ROLE_ID','ROLE_NAME'), 'inner');
//echo $sqlSelect->getSqlString(); exit;
$resultSet = $this->tableGateway->selectWith($sqlSelect);
if (! $resultSet) {
throw new \Exception ( "Could not find row $empFunctionId" );
}
return $resultSet->toArray();
}
In your class inherited from AbstractTableGateway u can use Select with Closure like this:
use Zend\Db\Sql\Select;
...
public function getAllBlockSettings()
{
$resultSet = $this->select(function(Select $select) {
$select->join('users', 'blogs_settings.owner_id = users.user_id', array('username'));
});
return $resultSet;
}
Give it a try:
namespace Object\Model;
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Sql\Select;
class BlogsSettingsTbl extends AbstractTableGateway {
public function __construct($adapter) {
$this->table = 'blogs_settings';
$this->adapter = $adapter;
$this->initialize();
}
public function fetchAll() {
$where = array(); // If have any criteria
$result = $this->select(function (Select $select) use ($where) {
$select->join('users', 'blogs_settings.owner_id = users.user_id', array('username'));
//echo $select->getSqlString(); // see the sql query
});
return $result;
}
}
Add to 'getServiceConfig()' in Module.php:
'Object\Model\BlogsSettingsTbl' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new BlogsSettingsTbl($dbAdapter); // <-- also add this to 'USE' at top
return $table;
},
since the OP hasn't accepted any answer, I'll try to give the solution.
I face the same solution as the OP states and the only way to fix it is by adding this line to the model class (in this case this might be 'Blogsetttings.php').
$this->username= (!empty($data['username'])) ? $data['username'] : null;
you should add above line to the exchangeArray() method.
Hope it helps