CakePHP controller method to fetch data from multiple related tables - cakephp

Currently i am working with CakePHP 3.x and have a following use case.
Department (id, name, description)
Designations (id, name, description)
Users (id, name, description)
DepartmentDesignations (id, departments_id, designations_id)
DepartmentDesignationUsers (id, department_designations_id, users_id)
Above mentioned are 5 different tables and their columns are listed in brackets. Following is the relationship between these.
Department has many designations. So in order to handle this i have created another DepartmentDesignations.
DepartmentDesignations has many users. So in order to handle this i have created DepartmentDesignationUsers.
I have defined following function in DepartmentsController and my expectation is that i need to get all the following information in single call.
- all the departments
- all the designations in each department (if any)
- all the users for each department designation (if any)
public function index()
{
$departments = $this->Departments->find('all')
->contain('DepartmentDesignations.Designations')
->contain('Users');
$this->set(compact('departments'));
$this->set('_serialize', ['departments']);
}
I have also defined the following in DepartmentsTable.php
$this->belongsToMany('Designations', [
'joinTable' => 'department_designations',
'foreignKey' => 'departments_id',
'targetForeignKey' => 'designations_id'
]);
$this->hasMany('DepartmentDesignations', [
'className' => 'OrganizationManagement.DepartmentDesignations',
'foreignKey' => 'departments_id'
]);
$this->hasMany('DepartmentDesignationUsers',[
'className' => 'OrganizationManagement.DepartmentDesignationUsers',
'foreignKey' => 'department_designations_id'
]);
$this->belongsToMany('Users',[
'joinTable' => 'department_designation_users',
'foreignKey' => 'department_designations_id',
'targetForeignKey' => 'users_id'
]);
I get the following response.
{
"departments": [
{
"id": 1,
"name": "Organization",
"description": "",
"parent_id": 0,
"users": [],
"department_designations": [
{
"id": 1,
"departments_id": 1,
"designations_id": 1,
"designation": {
"id": 1,
"name": "Brand head",
"description": "",
"level": 1
}
},
{
"id": 6,
"departments_id": 1,
"designations_id": 6,
"designation": {
"id": 6,
"name": "CEO",
"description": "",
"level": 1
}
}
]
},
{
"id": 2,
"name": "Production",
"description": "",
"parent_id": 1,
"users": [],
"department_designations": [
{
"id": 3,
"departments_id": 2,
"designations_id": 5,
"designation": {
"id": 5,
"name": "Production assistant manager",
"description": "",
"level": 3
}
},
{
"id": 5,
"departments_id": 2,
"designations_id": 4,
"designation": {
"id": 4,
"name": "Production head",
"description": "",
"level": 2
}
}
]
},
{
"id": 3,
"name": "R&D",
"description": "",
"parent_id": 1,
"users": [],
"department_designations": [
{
"id": 2,
"departments_id": 3,
"designations_id": 2,
"designation": {
"id": 2,
"name": "R&D Manager",
"description": "",
"level": 2
}
}
]
},
{
"id": 4,
"name": "Development",
"description": "",
"parent_id": 3,
"users": [],
"department_designations": [
{
"id": 4,
"departments_id": 4,
"designations_id": 2,
"designation": {
"id": 2,
"name": "R&D Manager",
"description": "",
"level": 2
}
}
]
},
{
"id": 5,
"name": "Purchase",
"description": "",
"parent_id": 1,
"users": [],
"department_designations": []
}
]
}
I need the user information within department_designations array. So in this case what changes i need to do.

On the basis of your information there is no direct relation between
Departments and Users table, So you can not use contain that way for users.
Make it something like this:
public function index()
{
$departments = $this->Departments->find('all')
->contain('DepartmentDesignations.Designations','DepartmentDesignations.DepartmentDesignationUsers.Users');
$this->set(compact('departments'));
$this->set('_serialize', ['departments']);
}
See here: Retrieving Associated Data in CakePHP3.

Related

Array : Replace part of array object with other array object

I have an array :
{
"count": 8,
"id": "accountId",
"name": " Account Id",
"values": [
{
"count": 2,
"id": "1234456789000",
"name": "1234456789000"
},
{
"count": 1,
"id": "135792468045",
"name": "135792468045"
},
{
"count": 1,
"id": "309983110022",
"name": "309983110022"
},
{
"count": 2,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 1,
"id": "6ee26149-a156-4665-bd26-a6e46b49a70f",
"name": "6ee26149-a156-4665-bd26-a6e46b49a70f"
},
{
"count": 1,
"id": "927b48ce-efe4-4c20-98f0-ec6c54f59b45",
"name": "927b48ce-efe4-4c20-98f0-ec6c54f59b45"
}
]
}
And I have a 2nd array :
[
{
"count": 2,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 2,
"id": "1234456789000",
"name": "1234456789000"
}
]
The second array, I have filtered based on some requirement.
I want to replace the values from 1st array with second array.
Using typescript code.
Please help here.
If I understand question, you just need iterate by values array and find same id from second array.
function findAndSwitch(object1, array1): void {
object1.values = object1.values.map(el => {
const objToSwitch = array1.find(eleArr => eleArr.id === el.id);
if (objToSwitch) {
return el = objToSwitch;
} else {
return el;
}
});
}
https://stackblitz.com/edit/typescript-dvty4p
Let's say your variable names are obj1 and arr2, respectively. First transform arr2 into an object obj2:
let obj2 = arr2.reduce((acc,cur) => ({...acc,[cur.id]:cur}),{});
Which now looks like this:
{
'432112426686': {
count: 20,
id: '432112426686',
name: '432112426686'
},
'1234456789000': {
count: 20,
id: '1234456789000',
name: '1234456789000'
}
}
Then transform obj1 based on obj2 as follows:
obj1.values = obj1.values.map(value => obj2[value.id] || value);
Please note that since the data in arr2 is identical to the corresponding data in obj1, I have altered the values of count property in arr2 in order to demonstrate that obj1 will be updated accordingly.
DEMO ONE
let obj1 = {
"count": 8,
"id": "accountId",
"name": " Account Id",
"values": [
{
"count": 2,
"id": "1234456789000",
"name": "1234456789000"
},
{
"count": 1,
"id": "135792468045",
"name": "135792468045"
},
{
"count": 1,
"id": "309983110022",
"name": "309983110022"
},
{
"count": 2,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 1,
"id": "6ee26149-a156-4665-bd26-a6e46b49a70f",
"name": "6ee26149-a156-4665-bd26-a6e46b49a70f"
},
{
"count": 1,
"id": "927b48ce-efe4-4c20-98f0-ec6c54f59b45",
"name": "927b48ce-efe4-4c20-98f0-ec6c54f59b45"
}
]
};
let arr2 = [
{
"count": 20,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 20,
"id": "1234456789000",
"name": "1234456789000"
}
];
let obj2 = arr2.reduce((acc,cur) => ({...acc,[cur.id]:cur}),{});
obj1.values = obj1.values.map(value => obj2[value.id] || value);
console.log( obj1 );
--
However, if all you want is to replace all the obj1.values with arr2, all you need is:
obj1.values = [...arr2];
And this will give rise to:
{
count: 8,
id: 'accountId',
name: ' Account Id',
values: [{
count: 20,
id: '432112426686',
name: '432112426686'
},
{
count: 20,
id: '1234456789000',
name: '1234456789000'
}
]
}
DEMO TWO
let obj1 = {
"count": 8,
"id": "accountId",
"name": " Account Id",
"values": [
{
"count": 2,
"id": "1234456789000",
"name": "1234456789000"
},
{
"count": 1,
"id": "135792468045",
"name": "135792468045"
},
{
"count": 1,
"id": "309983110022",
"name": "309983110022"
},
{
"count": 2,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 1,
"id": "6ee26149-a156-4665-bd26-a6e46b49a70f",
"name": "6ee26149-a156-4665-bd26-a6e46b49a70f"
},
{
"count": 1,
"id": "927b48ce-efe4-4c20-98f0-ec6c54f59b45",
"name": "927b48ce-efe4-4c20-98f0-ec6c54f59b45"
}
]
};
let arr2 = [
{
"count": 20,
"id": "432112426686",
"name": "432112426686"
},
{
"count": 20,
"id": "1234456789000",
"name": "1234456789000"
}
];
obj1.values = arr2;
console.log( obj1 );

Filter an array of obj based on another array value

I have an array of object like this :
[
{
"url": "https://recipes-gatsby-react.netlify.app/",
"stack": [
{
"id": 1,
"title": "GatsbyJs"
},
{
"id": 2,
"title": "React"
},
{
"id": 3,
"title": "GraphQl"
}
],
"id": "Project_1",
"featured": false,
"title": "Gatsby recipes app"
},
{
"url": "https://resort-react-mr.netlify.app",
"stack": [
{
"id": 4,
"title": "React"
},
{
"id": 5,
"title": "Contentful"
}
],
"id": "Project_2",
"featured": false,
"title": "react resort"
},
{
"url": "https://color-generator-react-mr.netlify.app/",
"stack": [
{
"id": 6,
"title": "React"
}
],
"id": "Project_3",
"featured": false,
"title": "color generator"
},
{
"url": "",
"stack": [
{
"id": 7,
"title": "React Native"
},
{
"id": 8,
"title": "Firebase"
}
],
"id": "Project_4",
"featured": false,
"title": "Book-Worm"
},
{
"url": "",
"stack": [
{
"id": 9,
"title": "React Native"
},
{
"id": 10,
"title": "Firebase"
},
{
"id": 11,
"title": "Stripe"
},
{
"id": 12,
"title": "Google Api"
}
],
"id": "Project_5",
"featured": false,
"title": "Delivery App"
},
{
"url": "https://cocktails-react-app-mr.netlify.app/",
"stack": [
{
"id": 13,
"title": "React"
}
],
"id": "Project_6",
"featured": false,
"title": "Cocktails App"
},
{
"url": "https://www.ideacasaitalia.it/index.php",
"stack": [
{
"id": 14,
"title": "Prestashop"
}
],
"id": "Project_7",
"featured": false,
"title": "Idea Casa Italia"
}
]
and I have another (simple) array like this one for example
["react","prestashop"]
I would like to filter the first array based on STACK key on the value of the second array, i.e. I would like to be returned all elements that have at least one element of the array (variable).
I have come to this
const filter = value => {
const newProj = relProjects.filter(obj =>
obj.stack.some(st => st.title.toLowerCase().includes(value))
)
setProjRel(newProj)
}
console.log(filter(["react","prestashop"])
however in this way I can only get the elements that contain all the elements of the array. Instead I would like to have returned all the elements that have AT LEAST 1 stack of the ones I passedThanks to who will answer me
Using Array#filter and Array#includes
Filter through the data array. With the predicate being that the stack array has at least one item that is included in the matches array
const data = [{"url":"https://recipes-gatsby-react.netlify.app/","stack":[{"id":1,"title":"GatsbyJs"},{"id":2,"title":"React"},{"id":3,"title":"GraphQl"}],"id":"Project_1","featured":false,"title":"Gatsby recipes app"},{"url":"https://resort-react-mr.netlify.app","stack":[{"id":4,"title":"React"},{"id":5,"title":"Contentful"}],"id":"Project_2","featured":false,"title":"react resort"},{"url":"https://color-generator-react-mr.netlify.app/","stack":[{"id":6,"title":"React"}],"id":"Project_3","featured":false,"title":"color generator"},{"url":"","stack":[{"id":7,"title":"React Native"},{"id":8,"title":"Firebase"}],"id":"Project_4","featured":false,"title":"Book-Worm"},{"url":"","stack":[{"id":9,"title":"React Native"},{"id":10,"title":"Firebase"},{"id":11,"title":"Stripe"},{"id":12,"title":"Google Api"}],"id":"Project_5","featured":false,"title":"Delivery App"},{"url":"https://cocktails-react-app-mr.netlify.app/","stack":[{"id":13,"title":"React"}],"id":"Project_6","featured":false,"title":"Cocktails App"},{"url":"https://www.ideacasaitalia.it/index.php","stack":[{"id":14,"title":"Prestashop"}],"id":"Project_7","featured":false,"title":"Idea Casa Italia"}];
const matches = ["react", "prestashop"];
const filtered = data.filter(({ stack }) => stack.filter(({ title }) => matches.includes(title.toLowerCase())).length > 0);
console.log(filtered);

Avoid using arrays (and [0]) in multidimensional JSON object

I'm storing data in a JSON file and need different objects/arrays. So far I am using the following structure:
data= [
{
"savedRuns": [
{
"id": 1,
"name": "Run 1"
},
{
"id": 2,
"name": "Run 2"
},
{
"id": 3,
"name": "Run 3"
}
]
},
{
"groups": [
{
"id": 1,
"name": "g1"
},
{
"id": 2,
"name": "g2"
},
{
"id": 3,
"name": "g3"
}
]
},
{
"locations": [
{
"id": 1,
"name": "home"
},
{
"id": 2,
"name": "work"
},
{
"id": 3,
"name": "school"
}
]
}
]
I would like to access the data in the file in an easy way, for instance:
console.log(data.savedRuns)
console.log(data.locations)
Unfortunately this returns undefined and the only way to access the data is:
console.log(data[0].savedRuns);
console.log(data[2].locations);
Since I don't necessarily know the position of the object, I would like to avoid that. If there a way around this, or a different structure to adopt for my file?
Link to JSFiddle
You have each attribute in a separate object, stored in an array. Get rid of the outer array and store the attributes in one object, then use data.savedRuns.
Thanks to Marks answer I could get the right syntax. Posting below in case of interest to others.
data = {
"savedRuns": [{
"id": 1,
"name": "Run 1"
},
{
"id": 2,
"name": "Run 2"
},
{
"id": 3,
"name": "Run 3"
}
],
"groups": [{
"id": 1,
"name": "g1"
},
{
"id": 2,
"name": "g2"
},
{
"id": 3,
"name": "g3"
}
],
"locations": [{
"id": 1,
"name": "home"
},
{
"id": 2,
"name": "work"
},
{
"id": 3,
"name": "school"
}
]
}

Resultset mapper or formatter in Cakephp 3

I have 2 Collections/ Result sets the first one is products and second one is sizes
"products": [
{
"category_id": 5,
"id": 5,
"code": "A",
"name": "Pizzabrot",
"description": "",
"product_prices": [
{
"product_id": 5,
"price": 2.5,
"size_id": 15
},
{
"product_id": 5,
"price": 3.5,
"size_id": 16
}
]
},
{
"category_id": 5,
"id": 6,
"code": "B",
"name": "Pizzabrot mit Knoblauch",
"description": "",
"product_prices": [
{
"product_id": 6,
"price": 3,
"size_id": 15
},
{
"product_id": 6,
"price": 4,
"size_id": 16
}
]
}]
AND
"sizes": [
{
"id": 15,
"name": "Klein",
"category_id": 5
},
{
"id": 16,
"name": "Gro\u00df",
"category_id": 5
}
]
I want to replace every product_prices.size_id with it's name from sizes Collection
From what I can see it would probably be better to associate ProductPrices and Sizes and fetch them with your Products.
If this does not fit your needs for some reason, you could find the sizes by using a find('list') (see Docs) like this:
$query = $this->Sizes->find('list', [
'keyField' => 'id',
'valueField' => 'name'
]);
$sizes = $query->toArray();
Then loop through the products and its product_prices and do something like.
$product_price->size_id = $sizes[$product_price->size_id];
Please prefer the first solution. ;-)

Get a list of all the competitors assigned in all the teams in VueJS

I have a list of teams. Each team has a list of assigned competitors.
Each team should have unique competitors.
How should I have the list of all the competitors assigned in VueJS???
"teams": [
{
"id": 25,
"name": "t1",
"competitors": [
{
"id": 1,
"short_id" : 1,
...
},
]
},
{
"id": 26,
"name": "t2",
"competitors": [
{
"id": 4,
"short_id" : 4,
...
},
{
"id": 3,
"short_id" : 3,
...
},
{
"id": 5,
"short_id" : 5,
...
},
]
},
{
"id": 28,
"name": "t3",
"competitors": []
}
]
new Vue({
el: "#app",
data:{
teams
},
computed:{
competitors(){
return this.teams.reduce((acc, team) => acc.concat(team.competitors), [])
}
}
})
Example.

Resources