How to union when using matching - union

I am trying to list public status posts and friends posts
getting friends post
$friendsPosts= $this->Posts->find('all')
->contain(['Users', 'Languages', 'PostStates'])
->matching('Users.Dusers', function ($q) {
return $q->where(['Dusers.id' => $this->Auth->user('id')]);
});
getting public post
$posts= $this->Posts->find('all')
->where(['Posts.post_state_id' => 3])
->contain(['Users', 'Languages', 'PostStates']);
$posts->union($friendsPosts);
dd($posts->toArray());
error message: The used SELECT statements have a different number of columns

Here is solution
$posts = $this->Posts->find()
->where(['Posts.post_state_id' => 3])
->contain(['Users', 'PostStates', 'Languages', 'Tags', 'Translations' => ['Users', 'Languages', 'conditions' => ['post_state_id' => 3]]]);
$friendsPosts = $this->Posts->find('all')
->where(['Posts.post_state_id' => 2])
->contain(['PostStates', 'Languages', 'Users', 'Tags', 'Translations' => ['Users', 'Languages', 'conditions' => ['post_state_id' => 3]]])
->innerJoinWith('Users.Dusers', function ($q) {
return $q->where(['Dusers.id' => $this->Auth->user('id'), 'UsersUsers.status' => 1])->select($this->Posts->Users);
});
$posts->union($friendsPosts);

Related

how to use Orderby in cakephp

I am trying to order data in accordance with its priority...
But this query is not working for me....
I cannot figure it out where it went wrong..
please help me to solve this..
$admins = $this->xxx->find()
->select($fields)
->where($conditions)
->contain([
'yyy' => function ($q) {
return $q->autoFields(false)
->select(['id','name','login_url','priority'])
->order(['priority' => 'ASC']);
}
])
->all();
If the realtionship between xxx and yyy is belongsTo then you have to move the order() method outside the contain
$admins = $this->xxx->find()
->select($fields)
->where($conditions)
->contain([
'yyy' => function ($q) {
return $q->autoFields(false)
->select(['id','name','login_url','priority']);
}
])
->order(['yyy.priority' => 'ASC'])
->all();
array(
'conditions' => array('Model.field' => $thisValue), //array of conditions
'recursive' => 1, //int
//array of field names
'fields' => array('Model.field1', 'DISTINCT Model.field2'),
//string or array defining order
'order' => array('Model.created', 'Model.field3 DESC'),
'group' => array('Model.field'), // fields to GROUP BY
'limit' => n, //int
'page' => n, //int
'offset' => n, //int
'callbacks' => true //other possible values are false, 'before', 'after'
'having' => array('COUNT(Model.field) >' => 1), // fields to HAVING by
'lock' => true // Enable FORM UPDATE locking
)

Laravel Missing Argument db:seed

I'm using Laravel. I'm creating my database and seed files. (not using Test Dummy) When I start the process of terminal and i got a Missing Argument errors.
khazax#khz ~/Code/Laravel $ php artisan db:seed
Seeded: UsersTableSeeder
Seeded: RolesTableSeeder
[ErrorException]
Missing argument 1 for Illuminate\Database\Eloquent\Builder::where()
khazax#khz ~/Code/Laravel $
DatabaseSeeder.php
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Model::unguard();
$this->call(UsersTableSeeder::class);
$this->call(RolesTableSeeder::class);
$this->call(PermissionsTableSeeder::class);
}
}
UsersTableSeeder.php
<?php
use App\Models\User;
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
public function run()
{
User::truncate();
User::create([
'first_name' => 'Onur',
'last_name' => 'Kaya',
'username' => 'Khazax',
'username_slug' => 'khazax',
'email' => 'onurkayaes#gmail.com',
'password' => bcrypt('123'),
'confirmation_code' => md5(microtime()+env('APP_KEY')),
'confirmed' => 1,
'settings' => [
'gender' => 'Erkek',
'phone' => '111',
'adress' => 'Eskisehir/Turkiye',
'home_page' => 'https://khazadum.com',
'opt_in_monhtly' => false,
'opt_in_quartly' => false,
'opt_in_year' => true
]
]);
User::create([
'first_name' => 'Tab',
'last_name' => 'Dev',
'username' => 'Tabdev',
'username_slug' => 'tabdev',
'email' => 'info#123.com',
'password' => bcrypt('123'),
'confirmation_code' => md5(microtime()+env('APP_KEY')),
'confirmed' => 1,
'settings' => [
'gender' => 'Erkek',
'phone' => '222',
'adress' => 'Istanbul/Turkey',
'home_page' => 'https://tabtusu.com',
'opt_in_monhtly' => false,
'opt_in_quartly' => false,
'opt_in_year' => true
]
]);
}
}
RolesTableSeeders.php
<?php
use App\Models\Role;
use App\Models\User;
use App\Models\AssignedRole;
use Illuminate\Database\Seeder;
class RolesTableSeeder extends Seeder
{
public function run()
{
Role::truncate();
$adminRole = new Role;
$adminRole->name = 'admin';
$adminRole->display_name = 'Administrator';
$adminRole->description = 'Tüm yetkilerin var olduğu kullanıcı grubu';
$adminRole->is_admin = 1;
$adminRole->save();
$userRole = new Role;
$userRole->name = 'user';
$userRole->display_name = 'User';
$userRole->description = 'Sadece site içi işlemleri yapabilen kullanıcı grubu';
$userRole->is_admin = 0;
$userRole->save();
$admin = User::where('email', 'onurkayaes#gmail.com')->first();
$assRoleAdmin = new AssignedRole;
$assRoleAdmin->user_id = $admin->id;
$assRoleAdmin->role_id = $adminRole->id;
$assRoleAdmin->save();
$user = User::where('email', 'info#123.com')->first();
$assRoleUser = new AssignedRole;
$assRoleUser->user_id = $user->id;
$assRoleUser->role_id = $userRole->id;
$assRoleUser->save();
}
}
and PermissionsTableSeeders.php
<?php
use App\Models\Permission;
use App\Models\Role;
use Illuminate\Database\Seeder;
class PermissionsTableSeeder extends Seeder
{
public function run()
{
Permission::truncate();
$permission = [
array(
'name' => 'manage_user',
'display_name' => 'Manage Users',
'is_admin' => 1
),
array(
'name' => 'manage_content',
'display_name' => 'Manage Content',
'is_admin' => 1
),
array(
'name' => 'manage_roles',
'display_name' => 'Manage User Roles',
'is_admin' => 1
),
array(
'name' => 'manage_files',
'display_name' => 'Manage Files',
'is_admin' => 1
)
];
foreach($permission as $row)
{
$row = array_merge($row, ['created_at' => new DateTime, 'updated_at' => new DateTime]);
DB::table('permissions')->insert($row);
}
$role_id_admin = Role::where()->first()->id;
$perm_base = (int)DB::table('permissions')->first()->id-1;
$perms = [
array(
'role_id' => $role_id_admin,
'permission_id' => $perm_base + 1
),
array(
'role_id' => $role_id_admin,
'permission_id' => $perm_base + 2
),
array(
'role_id' => $role_id_admin,
'permission_id' => $perm_base + 3
),
array(
'role_id' => $role_id_admin,
'permission_id' => $perm_base + 4
),
array(
'role_id' => $role_id_admin,
'permission_id' => $perm_base + 5
)
];
DB::table('permission_role')->delete();
foreach($perms as $row)
{
$row = array_merge($row, ['created_at' => new DateTime, 'updated_at' => new DateTime]);
DB::table('permission_role')->insert($row);
}
}
}
Am I missing some code or is this just a simple typo? Thanks in advance for helping.
The problem in your code is that line:
$role_id_admin = Role::where()->first()->id;
in PermissionsTableSeeder.
Depending on your logic it should look like this:
$role_id_admin = Role::first()->id;
or you should also add condition for this like this:
$role_id_admin = Role::where('name','admin')->first()->id;

Multiple count in ORM is not working

I want to get count of tenancies based on differnet times
$start_date = $end_date = $end_date1 = new \DateTime('first day of last month');
$start_date = $start_date->format('Y-m-01 00:00:00');
$end_date = $end_date->format('Y-m-t 23:59:59');
$end_date1 = $end_date1->format('Y-m-'. date('d') .' 23:59:59');
$start_date2 = $end_date2 = new \DateTime('now');
$start_date2 = $start_date2->format('Y-m-01 00:00:00');
$end_date2 = $end_date2->format('Y-m-d 23:59:59');
$tenancyDetails = $this
->find()
->select([
'total_last_month' => $this->find()->func()->count('Tenancy.id'),
'count_last_month' => $this->find()->func()->count('Tenancy1.id'),
'count_curr_month' => $this->find()->func()->count('Tenancy2.id'),
'Tenancy.created', 'Tenancy1.created', 'Tenancy2.created',
])
->leftJoin(['Tenancy1' => 'tenancy'],[
'Tenancy1.active' => 1,
'Tenancy1.stage !=' => 1,
'Tenancy1.company_id' => $id,
])
->leftJoin(['Tenancy2' => 'tenancy'],[
'Tenancy2.active' => 1,
'Tenancy2.stage !=' => 1,
'Tenancy2.company_id' => $id,
])
->where([
'Tenancy.active' => 1,
'Tenancy.stage !=' => 1,
'Tenancy.company_id' => $id,
])
->where(function ($exp, $q) use ($start_date, $end_date) {
return $exp->between('Tenancy.created', $start_date, $end_date);
})
->where(function ($exp, $q) use ($start_date, $end_date1) {
return $exp->between('Tenancy1.created', $start_date, $end_date1);
})
->where(function ($exp, $q) use ($start_date2, $end_date2) {
return $exp->between('Tenancy2.created', $start_date2, $end_date2);
})->toArray();
Here is what I get. The number of counts are the same. Eventhough the datesare different
[
(int) 0 => object(App\Model\Entity\Tenancy) {
'total_last_month' => (int) 4590,
'count_last_month' => (int) 4590,
'count_curr_month' => (int) 4590,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2016-03-01T10:57:21+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'Tenancy1' => [
'created' => '2016-03-01 10:57:21'
],
'Tenancy2' => [
'created' => '2016-04-04 10:59:42'
],
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Tenancy'
}
]
Even though I have written the query this way but still the same problem.
$query = $tenancies->find();
$query->select([
'total_last_month' => $query->func()->count('Tenancy.id'),
])
->where([
'Tenancy.active' => 1,
'Tenancy.stage !=' => 1,
'Tenancy.company_id' => $id,
])
->where(function ($exp) use ($start_date, $end_date) {
return $exp->between('Tenancy.created', $start_date, $end_date);
});
$query->select([
'count_last_month' => $query->func()->count('Tenancy1.id'),
])
->leftJoin(['Tenancy1' => 'tenancy'],[
'Tenancy1.company_id' => $id,
])
->where([
'Tenancy1.active' => 1,
'Tenancy1.stage !=' => 1,
])
->where(function ($exp) use ($start_date, $end_date1) {
return $exp->between('Tenancy1.created', $start_date, $end_date1);
});
I can see the printed query which is correct.
After looking at all the examples in the documentation it looks like you need to instantiate the ORM query builder instance before using the func() helpers.
http://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functions
In theory $this->func() should work the same if the return is simply a string. but maybe using $this->func() results in a disconnect between the query instance you are trying to build and an unbound new instance?
try:
$tenancyDetails = $this>find();
$tenancyDetails->select([
'total_last_month' => $tenancyDetails->find()->func()->count('Tenancy.id'),
'count_last_month' => $tenancyDetails->find()->func()->count('Tenancy1.id'),
'count_curr_month' => $tenancyDetails->find()->func()->count('Tenancy2.id'),
'Tenancy.created',
'Tenancy1.created',
'Tenancy2.created',
])......
Edit
I checked the code for the count function in /ORM/query.php file.
If no values are set cake will perform the count() query on the call $this->func->count(). The PHP compiler must be reading and therefore executing the count query before the query has been built, meaning before your conditions have been set. That's why you you need to instantiate the class first to stop the count query executing prematurely.

Mock auth cakephp 3

Currently I'm trying to test a controller which uses the authentication component to retrieve the user id. Since I'm fairly new to unit/integration testing, I have no idea how to make this working. Moreover, all the content that I could find for this particular problem is written for Cakephp version 2.
Controller function:
public function favorite(){
// Particular line where the problem is occurring:
$userId = $this->Auth->User()['id'];
// Get all favorite pictures of the user
$query = $this->UsersPictures->getFavoritePictures($userId);
$results = $query->all();
// Replace the link in the result set by a presigned url of Amazon
foreach($results as $result){
$result->picture->link = $this->Aws->getTokenizedItem($result->picture->link);
}
$this->set([
'success' => true,
'data' => [
'pictures' => $results
],
'_serialize' => ['success', 'data']
]);
}
Integration test:
public function testFavoriteShouldPass(){
$this->configRequest([
'headers' => [
'Accept' => 'application/json'
]
]);
$this->get('api/pictures/favorite/1.json');
$expected = [
'success' => true,
'data' => [
[
'user_id' => 1,
'picture_id' => 1,
'created' => '2016-04-03T20:35:40+0000',
'modified' => '2016-04-03T20:35:40+0000',
'picture' => [
'id' => 1,
'album_id' => 1,
'description' => 'Lorem ipsum dolor sit amet',
'link' => 'test',
'favorite' => true,
'created' => null,
'modified' => null,
'cover_photo' => true
]
]
]
];
$this->assertEquals($expected, $response);
}
My question is how can I insert a user with a default id of 1 for $this->Auth->User()['id']. I saw in other questions that I need to use something that looks like this:
$this->_controller->Auth
->staticExpects($this->any())
->method('user')
->will($this->returnValue([
'id' => 1,
'username' => 'admin',
'created' => '2013-05-08 00:00:00',
'modified' => '2013-05-08 00:00:00',
'email' => 'me#me.com',
]));
However, I read that staticExpects is deprecated from phpunit version 3.8 (I'm using 5.2). How should I mock this?
You can set the session data in your integration tests using $this->session(), for example (taken from cakephp book):
// Set session data
$this->session([
'Auth' => [
'User' => [
'id' => 1,
'username' => 'testing',
// other keys.
]
]
]);
You can actually find it in their docs: http://book.cakephp.org/3.0/en/development/testing.html#controller-integration-testing
You can find it in the section
Testing Actions That Require Authentication
If you want to use the same session data on each test you can use the setUp method of your integration test class, like so:
public function setUp()
{
parent::setUp();
// Set session data
$this->session([
'Auth' => [
'User' => [
'id' => 1,
'username' => 'testing',
// other keys.
]
]
]);
}
With thanks to azahar :), this worked for me:
public function controllerSpy($event)
{
parent::controllerSpy($event);
if (isset($this->_controller)) {
$this->_controller->Auth->setUser([
'id' => 1,
'username' => 'testtesttesttest',
'email' => 'john#doe.com',
'first_name' => 'John',
'last_name' => 'Doe',
'uuid' => 'wepoewoweo-ew-ewewpoeopw',
'sign_in_count' => 1,
'current_sign_in_ip' => '127.0.0.1',
'active' => true
]);
}
}

How to get only selected fields from contain in cakephp3

I have a query as below but I need only certain fields not all the fields. I have set the autoFields to false but the query still returns all the fields.
$tenancies = $this
->find('all')
->autoFields(false)
->select([
'Tenancy.id', 'Tenancy.created', 'Tenancy.stage',
'Properties.id', 'Properties.address1', 'Properties.postcode',
'Tenants.stage',
])
->contain('Properties', function(\Cake\ORM\Query $query) {
return $query->where([
'Properties.active' => 1
]);
})
->contain(['Tenants'])
->leftJoinWith('Tenants', function(\Cake\ORM\Query $query) {
return $query
->autoFields(false)
->select([
'id', 'stage'
])
->where([
'Tenants.active' => 1
]);
})
->where([
'Tenancy.active' => 1,
$conditions
])
->order([
'Tenancy.created' => 'DESC',
'Tenants.tenancy_id'
])
->group(['Properties.id'])
->autoFields(false);
return $tenancies;
Prints =>
object(App\Model\Entity\Tenancy) {
'id' => (int) 3934,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2016-03-20T18:25:20+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'stage' => (int) 2,
'tenants' => [
(int) 0 => object(Cake\ORM\Entity) {
'id' => (int) 8922,
'user_id' => (int) 56456,
'tenancy_id' => (int) 3934,
'needs_guarantor' => true,
'guarantor_id' => null,
'holding_fee' => (float) 0,
...
...
Note: Using matching or leftJoinWith I can select the fields that I need but it doesn't work on contain
The main answer is you need to set the associations correctly. Once the associations are set correctly you can print it as simple as this.
return $this->find()
->select([
'Property.id', 'Property.company_id', 'Property.address1', 'Property.address2',
'Property.address3','Property.postcode',
])
->contain([
'Tenancies' => function($q) {
return $q
->select([
'Tenancies.id','Tenancies.property_id','Tenancies.created',
'Tenancies.stage',
])
->contain([
'Tenants' => function($q) {
return $q
->select([
'Tenants.id', 'Tenants.stage', 'Tenants.tenancy_id', 'Tenants.holding_fee',
])
->where([
'active = 1',
]);
}
])
->contain([
'Tenants'
])
->where([
'Tenancies.active = 1',
]);
}
])
->where(['Property.active = 1', $conditions])
->toArray();

Resources