remove & take out from the null entry - php

I have a project & branches model in Laravel, each project has many branches.
this function is work very well but it saved Empty records from $request->branches
$data = $request->except('branches');
$branches = collect($request->branches)->transform(function($branch) {
$branch['name'] = $branch['name'];
return new Branch($branch);
});
$data = $request->except('branches');
$data['user_id'] = $user->id;
$project = Project::create($data);
$project->branches()->saveMany($branches);
return response()->json(['created' => true,]);
I want to remove empty record from branches request.
this is the log of array:
$request->branches:
local.INFO: array (
0 =>
array (
'name' => NULL,
),
)
$branches (after collect) :
local.INFO: [{"name":null}]

You can use the filter function
$filteredBranches = $branches->filter();
See Documention.

I use the reject function
->reject(function ($branch) {return empty($branch['name']);})

Related

Laravel: php match does not seem to be working

I'm working on a Laravel app. I've created an enum like this:
<?php
namespace Domain\Order\Enums;
use Domain\Order\Models\Order;
enum OrderStatuses : string
{
case New = 'new';
case Pending = 'pending';
case Canceled = 'canceled';
case Paid = 'paid';
case PaymentFailed = 'payment-failed';
public function createOrderStatus(Order $order) : OrderStatus
{
return match($this) {
OrderStatuses::Pending => new PendingOrderStatus($order),
OrderStatuses::Canceled => new CanceledOrderStatus($order),
OrderStatuses::Paid => new PaidOrderStatus($order),
OrderStatuses::PaymentFailed => new PaymentFailedOrderStatus($order),
default => new NewOrderStatus($order)
};
}
}
In my order model I've got the following attribute:
protected function status(): Attribute
{
return new Attribute(
get: fn(string $value) =>
OrderStatuses::from($value)->createOrderStatus($this),
);
}
which as you can see receives some data and returns an Order status.
Now, I've got the following piece of code:
$order = Order::find($orderID);
$newOrder = match ($order->status) {
OrderStatuses::New => (new NewToPaidTransition)->execute($order),
NewOrderStatus::class => (new NewToPaidTransition)->execute($order),
'new' => (new NewToPaidTransition)->execute($order),
default => null,
};
but the value of $newOrder is always null, meaning the status is not being matched to any of the elements. There should be one single element there: NewOrderStatus::class, I just added the others for debugging purposes.
If I inspect the value of $order->status while running the debugger I'm getting that it is of type Domain\Order\Enums\NewOrderStatus so why it is not being matched?
Thanks
It looks like you are testing for equality between an instance of a class and a string of the class name.
Try
$newOrder = match (get_class($order->status)) {
OrderStatuses::New => (new NewToPaidTransition)->execute($order),
NewOrderStatus::class => (new NewToPaidTransition)->execute($order),
'new' => (new NewToPaidTransition)->execute($order),
default => null,
};

Laravel - keeping a running tally of a column through a transformer

So I have a Contribution model. I have a controller that pulls in all the contributions and sends them to a transformer like so:
My Controller:
public function showContributions (Request $request, $memberId)
{
$perPage = $request->input('per_page', 15);
$contribution = parent::getRepo('Contribution');
$contributions = Cache::tags(['contributions'])->remember("contributions.$memberId.2", 60, function() use ($perPage, $memberId, $contribution){
return $contribution->where('vip_id', $memberId)->where('fund_id', 2)->paginate($perPage);
});
$transformedData = $this->fractal->paginatedCollection($contributions, new ContributionTransformer(), 'contributions');
return $this->sendResponse($transformedData['contributions'], $transformedData['meta']);
}
My transformer:
public function transform(Contribution $contribution)
{
setlocale(LC_MONETARY, 'en_US.UTF-8'); // Set so that money_format uses the dollar sign instead of USD. Consider moving to bootstrap
$report = $contribution->report;
$employer = $report->employer;
$employerHours = $contribution->employerHours;
$contributionLocal = $contribution->local->local_code ?? '';
$employerLocal = $employerHours->local->local_code ?? '';
$reciprocalLocal = $contributionLocal === $employerLocal ? '0000' : $employerLocal;
$response = [
'id' => $contribution->member_hours_id,
'report_number' => $contribution->report_number_id,
'employer_code' => $employer->employer_code,
'employer_name' => $employer->employer_name,
'worked_date' => $report->ending_worked_date,
'received_date' => $report->receipt_date,
'report_local' => $contributionLocal,
'reciprocal_local' => $reciprocalLocal,
'unit_type' => $contribution->unitType->code_description,
'units_worked' => $contribution->units_worked,
'credited_units' => $contribution->units_credited,
'rate' => $contribution->unit_multiplier,
'reciprocal_rate' => $employerHours->reciprocal_multiplier,
'calculated_amount' => money_format('%.2n', $contribution->calculated_amount),
'received_amount' => money_format('%.2n', $contribution->actual_amount),
'owed_amount' => money_format('%.2n', $contribution->owed_amount),
];
return $response;
}
One of the fields in the contributions table is sub_hours. What they want me to do is keep a running tally of said field. In each subsequent row return that tally as hours_to_date. So in first row sub_hours is 32 and in the second row it is 60. In the first row hours_to_date will be 32 but in the second row it will be 92 and the third row it will be 92 + sub_hours of row 3 etc. I can't seem to figure out how I should keep track of this running tally and allow the transformer access to it. Any help would be appreciated.
Can you create a property on the transformer class? I haven't used transformers but something like
class ContributionTransformer{
private $tally;
function __construct(){
$this->tally = 0;
}
public function transform(Contribution $contribution){
...
$this->tally += $contribution->sub_hours;
...
}

Laravel and a While Loop

I'm new to Laravel and at the moment I have a piece of code in a Controller which without the while loop it works, it retrieves my query from the database.
public function dash($id, Request $request) {
$user = JWTAuth::parseToken()->authenticate();
$postdata = $request->except('token');
$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
if($q->num_rows > 0){
$check = true;
$maps = array();
while($row = mysqli_fetch_array($q)) {
$product = array(
'auth' => 1,
'id' => $row['id'],
'url' => $row['url'],
'locationData' => json_decode($row['locationData']),
'userData' => json_decode($row['userData']),
'visible' => $row['visible'],
'thedate' => $row['thedate']
);
array_push($maps, $product);
}
} else {
$check = false;
}
return response()->json($maps);
}
I am trying to loop through the returned data from $q and use json_decode on 2 key/val pairs but I can't even get this done right.
Don't use mysqli to iterate over the results (Laravel doesn't use mysqli). Results coming back from Laravel's query builder are Traversable, so you can simply use a foreach loop:
$q = DB::select('...');
foreach($q as $row) {
// ...
}
Each $row is going to be an object and not an array:
$product = array(
'auth' => 1,
'id' => $row->id,
'url' => $row->url,
'locationData' => json_decode($row->locationData),
'userData' => json_decode($row->userData),
'visible' => $row->visible,
'thedate' => $row->thedate
);
You're not using $postdata in that function so remove it.
Do not use mysqli in Laravel. Use models and/or the DB query functionality built in.
You're passing the wrong thing to mysqli_fetch_array. It's always returning a non-false value and that's why the loop never ends.
Why are you looping over the row data? Just return the query results-- they're already an array. If you want things like 'locationData' and 'userData' to be decoded JSON then use a model with methods to do this stuff for you. Remember, with MVC you should always put anything data related into models.
So a better way to do this is with Laravel models and relationships:
// put this with the rest of your models
// User.php
class User extends Model
{
function maps ()
{
return $this->hasMany ('App\Map');
}
}
// Maps.php
class Map extends Model
{
// you're not using this right now, but in case your view needs to get
// this stuff you can use these functions
function getLocationData ()
{
return json_decode ($this->locationData);
}
function getUserData ()
{
return json_decode ($this->userData);
}
}
// now in your controller:
public function dash ($id, Request $request) {
// $user should now be an instance of the User model
$user = JWTAuth::parseToken()->authenticate();
// don't use raw SQL if at all possible
//$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
// notice that User has a relationship to Maps defined!
// and it's a has-many relationship so maps() returns an array
// of Map models
$maps = $user->maps ();
return response()->json($maps);
}
You can loop over $q using a foreach:
foreach ($q as $row) {
// Do work here
}
See the Laravel docs for more information.

Unable to save select box options in Laravel 5.1

I am working on my first project using Laravel 5.1. Uses a selectbox in a form.
{!!Form::select('animal_parent[]', array('1' => 'opt1', '2' => 'opt2', '3' => 'opt3', '4' => 'opt4',), null, ['id' => 'animal_parent', 'disabled' => 'disabled', 'multiple' => 'multiple', 'class' => 'form-control'])!!}
Selection limited to two options which need to saved in two columns, male_parent and female_ parent of the animal table.
There are no male_parent and female_ parent element names in the form. Similarly no animal_parent field in animal table.
Values are set as expected in the code given below. However, the insert command does not reflect the newly set values and throws an error.
"ErrorException in helpers.php line 671: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array."
Any help would be much appreciated.
First attempt using mutators
public function setMaleParentAttribute()
{
$parent = Input::get('animal_parent');
$this->attributes['male_parent'] = intval($parent[0]);
}
public function setFemaleParentAttribute(AddAnimalRequest $request)
{
$parent = Input::get('animal_parent);
if (isset($parent[1])) {
$this->attributes['female_parent'] = intval($parent[1]);
} else {
$this->attributes['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
}
Second attempt using the store() method in the controller.
$animal = new Animal($request->all());
$parent = Input::get('animal_parent');
$animal['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$animal['female_parent'] = intval($parent[1]);
} else {
$animal['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
Auth::user()->animals()->save($animal);
return redirect('animals');
The problem was then solved with a change in UI. I feel the problem could have been solved using the below method. Hope that helps someone.
$input = $request->all();
$parent = $input['animal_parent'];
$input['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$input['female_parent'] = intval($parent[1]);
} else {
$input['female_parent'] = intval($parent[0]);
}
unset($input['animal_parent']);
$animal = new Animal($input);
$animal->save();`

How do you remove specific fields from all entities of a record set in Lithium?

I am using MySQL as the database connection adapter for all my models. I have a downloads model and controller with an index function that renders either an HTML table or a CSV file depending on the type passed from the request. I also have a CSV media type to handle an array of data, which is working as expected (outputs array keys as headers then array values for each row of data).
I wish to do the same find query but then remove ID fields from the record set if a CSV file is going to be rendered. You'll notice that the download ID is being fetched even though it is not in the fields array, so simply changing the fields array based on the request type will not work.
I have tried the following in the index action of my downloads controller:
<?php
namespace app\controllers;
use app\models\Downloads;
class DownloadsController extends \lithium\action\Controller {
public function index() {
// Dynamic conditions
$conditions = array(...);
$downloads = Downloads::find('all', array(
'fields' => array('user_id', 'Surveys.name'),
'conditions' => $conditions,
'with' => 'Surveys',
'order' => array('created' => 'desc')
));
if ($this->request->params['type'] == 'csv') {
$downloads->each(function ($download) {
// THIS DOES NOT WORK
unset($download->id, $download->user_id);
// I HAVE TRIED THIS HERE AND THE ID FIELDS STILL EXIST
// var_dump($download->data());
// exit;
return $download;
});
return $this->render(array('csv' => $downloads->to('array')));
}
return compact('downloads');
}
}
?>
I thought there was an __unset() magic method on the entity object that would be called when you call the standard PHP unset() function on an entity's field.
It would be great if there was a $recordSet->removeField('field') function, but I can not find one.
Any help would be greatly appreciated.
Perhaps you should do $downloads = $downloads->to('array');, iterate the array with a for loop, remove those fields from each row, then return that array. If you have to do this same thing for a lot of actions, you could setup a custom Media handler that could alter the data without needing logic for it in your controller.
Take a look at this example in the Lithium Media class unit test.
You can also avoid having much logic for it in your controller at all through the use of a custom handler. This example also auto-generates a header row from the keys in your data.
In config/bootstrap/media.php:
Media::type('csv', 'application/csv', array(
'encode' => function($data, $handler, $response) {
$request = $handler['request'];
$privateKeys = null;
if ($request->privateKeys) {
$privateKeys = array_fill_keys($request->privateKeys, true);
}
// assuming your csv data is the first key in
// the template data and the first row keys names
// can be used as headers
$data = current($data);
$row = (array) current($data);
if ($privateKeys) {
$row = array_diff_key($row, $privateKeys);
}
$headers = array_keys($row);
ob_start();
$out = fopen('php://output', 'w');
fputcsv($out, $headers);
foreach ($data as $record) {
if (!is_array($record)) {
$record = (array) $record;
}
if ($privateKeys) {
$record = array_diff_key($record, $privateKeys);
}
fputcsv($out, $record);
}
fclose($out);
return ob_get_clean();
}
));
Your controller:
<?php
namespace app\controllers;
use app\models\Downloads;
class DownloadsController extends \lithium\action\Controller {
public function index() {
$this->request->privateKeys = array('id', 'user_id');
// Dynamic conditions
$conditions = array(...);
$downloads = Downloads::find('all', array(
'fields' => array('user_id', 'Surveys.name'),
'conditions' => $conditions,
'with' => 'Surveys',
'order' => array('created' => 'desc')
));
return compact('downloads');
}
}
?>
Why not then just dynamically set your $fields array?
public function index() {
$type = $this->request->params['type'];
//Exclude `user_id` if request type is CSV
$fields = $type == 'csv' ? array('Surveys.name') : array('user_id', 'Surveys.name');
$conditions = array(...);
$with = array('Surveys');
$order = array('created' => 'desc');
$downloads = Downloads::find('all', compact('conditions', 'fields', 'with', 'order'));
//Return different render type if CSV
return $type == 'csv' ? $this->render(array('csv' => $downloads->data())) : compact('downloads');
}
You can see in this example how I send the array for your CSV handler, otherwise it's the $downloads RecordSet object that goes to the view.

Categories