Reputation: 55
I'm trying to build a project recommendation system, where users and projects have required skills tags. I'm trying to generate and sort a collection of recommended projects for users based on the amount of skills that match in each skill array, for example the project that has the most matching skills to users skills would be appear first in the list of recommended projects.
This is my code so far.
public function recommendedProjects()
{
$projects = Project::all()->filter(function ($project) {
foreach(unserialize($project->skills) as $projectSkill)
{
foreach(unserialize(Auth::user()->profile->skills) as $userSkill)
{
if($projectSkill === $userSkill)
{
return true;
}
}
}
});
return View::make('projects.projects')->with("title", "Recommended Projects")->with('projects', $projects);
}
So far it kinda works, but only returning projects with at least one matching skill.
It would also be helpful if I could limit the number of results to the most relevant 20 projects or so.
Any help is appreciated, this is my first Laravel project lol.
EDIT
I changed my code to store skills in their own table instead of using serialization, right now it returns all projects with at least one matching user skill.
I want to sort the projects so that projects with the most matching skills to user skills appear first.
for example, if a project has 3 required skills that the user has all 3 skills, the project would appear first, over a project with less matching skills.
here is my updated code
$projects = Project::all()->filter(function ($project) {
foreach ($project->skills as $projectSkill) {
foreach (Auth::user()->skills as $userSkill) {
if ($projectSkill->name === $userSkill->name) {
return true;
}
}
}
});
Upvotes: 0
Views: 2461
Reputation: 6319
You just need to sort the collection of projects you have. Try this:
$userSkills = Auth::user()->skills;
$projects = Projects::with('skills')->get();
$projects = $projects->sort(function($a, $b) use ($userSkills) {
// Get the matching skills from both A and B
$aMatchingSkills = $a->skills->intersect($userSkills);
$bMatchingSkills = $b->skills->intersect($userSkills);
// Return the count of A minus the count of B - See PHP uasort
return $aMatchingSkills->count() - $bMatchingSkills->count();
});
This is using the eloquent collection objects pretty extensively (sort
, intersect
and count
). sort
uses one very useful function from PHP - uasort
To remove projects that have no matching skills, try replacing the Projects::with('skills')->get();
bit with...
Projects::with(['skills' => function($q) use ($userSkills) {
$q->whereIn('name', $userSkills->fetch('name'));
}])->get();
This is getting a bit complex now and I can't guarantee that what I've posted will work, but it's close.
Upvotes: 3