Laravel Eloquent - updating a field in a relation - php

I'm looking for a better way of writing this. I feel like there must be a better way?
public static function logClick($lid)
{
$clickId = link::find($lid);
$clicks = click::find($clickId->click_id);
$c = $clicks->clicks;
$c++;
$clicks->clicks = $c;
$clicks->save();
return $clicks;
}
Models:
class link extends Model
{
public function click()
{
return $this->hasOne('App\click', 'id' ,'click_id');
}
}
class click extends Model
{
public function link()
{
return $this->hasOne('App\link');
}
}
Btw. everything works, just looking to improve my code writing :)

public static function logClick($lId){
click::whereHas('link', function($q)use($lId){
$q->where('id', $lId);
})
->increment('clicks');
}
This should do
EDIT: if you want to return the clicks number
public static function logClick($lId){
$click = click::whereHas('link', function($q)use($lId){
$q->where('id', $lId);
})
->increment('clicks');
return $click->clicks;
}
This one liner has the advantage of being a single query. In case $q->where('id', $lId); doesn't work, make sure to use $q->where('links_table_name.id', $lId);

public static function logClick($lid)
{
$clicks = link::find($lid)->click;
$clicks->increment('clicks');
return $clicks;
}

Related

Laravel - How to return data from two repositories

I'm trying to return two methods at once in the find function
public function find($id)
{
return AddRepository::findOrFail($id) &&
AddMeRepository::findOrFail($id);
}
public function find($id)
{
var result = [];
result['addRepository'] = AddRepository::findOrFail($id);
result['addMeRepository'] =AddMeRepository::findOrFail($id);
return result;
}
public static function find($id)
{
return array(AddRepository::findOrFail($id) ,AddMeRepository::findOrFail($id));
}
when you call method
list($add,$addme)=YourClass::find($id);
you can use $add and $addme variables.

Doctrine custom repository chaining filters?

What is the right way to chain custom repository methods in order to create one composed query that returns the entities based on multiple conditions.
Here is what I did:
use Doctrine\ORM\EntityRepository;
class ingredientRepository extends EntityRepository
{
private $query;
public function initNewQuery()
{
$this->query = $this->createQueryBuilder('i')->join('i.product', 'p');
return $this;
}
public function clearQuery()
{
$this->query = null;
return $this;
}
public function getResult(){
$r = $this->query->getQuery()->getResult();
$this->clearQuery();
return $r;
}
public function filterByProductName( $productName )
{
if(!$this->query) $this->initNewQuery();
$this->query->andWhere('p.name LIKE :name')->setParameter('name', '%'.$productName.'%');
return $this;
}
public function filterByMinContenu( $contenu )
{
if(!$this->query) $this->initNewQuery();
$this->query->andWhere('p.contenu > :contenu')->setParameter('contenu', $contenu);
return $this;
}
public function filterByType( $type ){
if(!$this->query) $this->initNewQuery();
$this->query->andWhere('i.type = :type')->setParameter('type', $type);
return $this;
}
}
This allows me to do things like:
$ingredients = $em->getRepository('ingredient')->initNewQuery()->filterByType(4)->getResult();
$ingredients = $em->getRepository('ingredient')->initNewQuery()->filterByProductName('ell')->filterByMinContenu(10)->getResult();
Which is exactly what I want !
But ... I don't really like it.
First, this is not how the default methods like findBy and so on work. These all return the results directly. So that doesn't seem right to mix those two behaviours.
And secondly, when calling only the filterByType method and then return the results, the query will use a join that it doesn't need. I guess I could find a way to do the join only if I need it, but again, doesn't seem right.
Any ideas on how to do this clean an simple ?
Fast answer without testing:)
use Doctrine\ORM\EntityRepository;
class ingredientRepository extends EntityRepository
{
private $query;
private function initNewQuery()
{
$this->query = $this->createQueryBuilder('i');
}
public function findBy($filterArray)
{
$this->initNewQuery();
if (array_key_exists('productName', $filterArray)) {
$this->filterByProductName($filterArray['productName']);
}
if (array_key_exists('minContenu', $filterArray)) {
$this->filterByMinContenu($filterArray['minContenu']);
}
if (array_key_exists('type', $filterArray)) {
$this->filterByType($filterArray['type']);
}
return $this->query->getQuery()->getResult();
}
private function filterByProductName($productName)
{
$this->query->join('i.product', 'p');
$this->query->andWhere('p.name LIKE :name')->setParameter('name', '%'.$productName.'%');
}
private function filterByMinContenu($contenu)
{
$this->query->andWhere('p.contenu > :contenu')->setParameter('contenu', $contenu);
}
private function filterByType($type)
{
$this->query->andWhere('i.type = :type')->setParameter('type', $type);
}
}
call:
$ingredients = $em->getRepository('ingredient')->findBy(['type'=>4]);
$ingredients = $em->getRepository('ingredient')->findBy(['productName'=>'ell', 'minContenu' => 10]);

How to access data of one function to another in laravel

Okay the issue is something like this
I have a function in AController
public function index()
{
$store = Store::(query)(to)(rows)->first();
return view('store.index', compact('store'));
}
Now in the same controller I have another function
public function abc()
{
return view('store.abc');
}
Now to this function I also want to send the compact('store') to the view abc I can just add the query again in the abc() function but that would be lazy and make performance issues. Is there a way that I can access $store object in other functions too?
If I understand you correctly you want to access the same query from two places. So extract getting stores to another method like
private function store()
{
$minutes = 10; // set here
return Cache::remember('users', $minutes, function () {
return Store::(query)(to)(rows)->first();
});
}
Additionally I have cached the query. So it get executed once at a defiened time.
Then access it from other two methods like,
public function index()
{
$store = $this->store();
return view('store.index', compact('store'));
}
public function abc()
{
$store = $this->store();
return view('store.abc', compact('store'));
}
class StoreController extends Controller
{
public function index()
{
return view('admin.store',['data' => $this->getSetting()]);
}
public function getStoreData()
{
//get your data here, for example
$data = Store::where('status',1)->first();
//get all data
//$data = Store::all();
return ($data);
}
}
Try the following. Not testing but it should work for you.
class AController
{
public function getStore()
{
$store = Store::(query)(to)(rows)->first();
return compact('store');
}
public function index()
{
return view('store.index', $this->getStore());
}
public function abc()
{
return view('store.abc', $this->getStore());
}
}

How to make a function usable for multiple instances? eg player1, player2,

It seems I forgot anything and now stuck an this little thing.
There is a match between multiple players in two teams. How do I have to write this function to make it handle every player?
Match.php
public function __construct()
{
$this->redTeam = new Team();
$this->blueTeam = new Team();
$this->player1 = new Player('Bensen');
$this->player2 = new Player('Kicksen');
$this->startMatch();
}
public function fightCreeps()
{
$creeps = 0;
$gold = 0;
for ($this->wave; $this->wave > 0; $this->wave--) {
if ($this->player1->lasthitting >= rand(1, 100)) {
$creeps++;
$gold += 40;
$this->player1->creeps++;
$this->player1->gold += 40;
$this->player1->totalGold += 40;
$this->player1->experience += 40;
$this->player1->health -= rand(5, 10);
}
}
return "<span style=\"color: red;\">{$this->player1->name}</span> has slain {$creeps} Creeps. +{$gold} Gold<br>";
}
I think you need to consider your app architecture. From an OOP point of view, the Match doesn't fightCreeps(), the Player fights creeps.
I would define the relations differently (see https://laravel.com/docs/5.1/eloquent-relationships). For example, if you know there are only ever going to be two teams playing in a Match, then on the Match model, you define:
use App\Team;
class Match extends Model {
protected static function boot()
{
parent::boot();
// when a match is created, auto-create teams
static::created(function ($match) {
$match->redTeam()->create([]);
$match->blueTeam()->create([]);
});
}
public function startMatch()
{
//fight
}
public function redTeam()
{
return $this->hasOne(Team::class);
}
public function blueTeam()
{
return $this->hasOne(Team::class);
}
}
Team model:
use App\Match;
use App\Player;
class Team extends Model {
protected static function boot()
{
parent::boot();
// when a team is created auto-add players
static::created(function ($team) {
$team->players()->create(['name' => 'Bensen']);
$team->players()->create(['name' => 'Kicksen']);
});
}
public function players()
{
return $this->hasMany(Player::class);
}
public function match()
{
return $this->belongsTo(Match::class);
}
}
Player Model:
use App\Team;
class Player extends Model {
public function team()
{
return $this->belongsTo(Team::class);
}
public function fightCreeps()
{
// fight!
}
}
Then, you can do things like:
foreach ($this->redTeam->players as $player) {
$player->fightCreeps();
}
You can, of course vary how you create the teams and players, but I think these are the general relationships that you want.
In Laravel relationships, multiple relations are automatically returned as a Collection (https://laravel.com/docs/5.1/collections), which is a fancier version of an array. If you want, you can manually create a collection yourself and then loop through it, like so:
$players = collect([$player1, $player2]);
foreach ($players as $player) {
// do something
}
public $players = [];
public function __construct()
{
$this->redTeam = new Team();
$this->blueTeam = new Team();
$this->addPlayer('Bensen');
$this->addPlayer('Kicksen');
$this->startMatch();
}
public function addPlayer($name)
{
$this->players[] = new Player($name);
}
public function startMatch()
{
// do other starting match related stuff
foreach ($this->players as $player) {
$this->fightCreeps($player);
}
}
public function fightCreeps(Player $player)
{
// do the fighting stuff
}

Another way to assign a function without executing it

Is there another way to assign or return a function without executing it? I think this is not the best solution ...
class Foo {
public function getDisplayFunction() {
return function() {
$this->display();
};
}
private function display() {
echo 'something';
}
}
$display = (new Foo())->getDisplayFunction();
//and execute it
$display();
I get it ... after trying 100 of things and 1 hour searching. Here my answer for all who looking also for the solution.
public function getDisplayFunction() {
return function() {
return $this->display();
}
}
is the same as:
public function getDisplayFunction() {
return [$this, 'display'];
}
the advantage is you don't have to pass args with this solution. That was the reason for the question.

Categories