How to optimize this data structure? - php

API result:
php laravel
the article_user and article_title is repeated.
i use transformer to transform my data.
public function transform(ArticleComment $comments)
{
$articleInfo = $comments->article;
$user = UserInfo::select('real_name')->find($articleInfo->created_user_id);
return [
'article_user' => $user->real_name,
'article_title' => $articleInfo->title,
'is_evaluator' => $comments->is_evaluation,
'comment_created_user' => $comments->user,
'created_at' => $comments->created_at,
'comment_content' => $comments->content,
'replied_comment' => $comments->reply,
'replied_user' => $comments->repliedUser,
];
}
}
i want it like this
article_info:{
article_user: "",
article_title: "",
}
article_comment:{
content: "",
is_evaluator: 0,
...
}
how to optimize it ?
what should i do ?
the response

You can use simple arrays to format your response. In your case it should be:
public function transform(ArticleComment $comments)
{
$articleInfo = $comments->article;
$user = UserInfo::select('real_name')->find($articleInfo->created_user_id);
return [
'article_info' => [
'article_user' => $user->real_name,
'article_title' => $articleInfo->title
],
'article_comment' => [
'is_evaluator' => $comments->is_evaluation,
'comment_created_user' => $comments->user,
'created_at' => $comments->created_at,
'comment_content' => $comments->content,
'replied_comment' => $comments->reply,
'replied_user' => $comments->repliedUser
]
];
}

Related

Craft CMS element-api how to get values of a category field in entry

Working on an element-api.php file from a Craft CMS project. Has a lot of helper functions. I added a category called disciplines. I'm trying to expose the values for each entry.
Here's the whole helper function I'm working on:
// Get all projects, by date, newest first
function getAllProjects() {
$caseStudies = [];
$query = \craft\elements\Entry::find();
$query->section('caseStudies');
$query->orderBy('postDate desc');
foreach ($query->all() as $page) {
$isPublic = $page->public;
$parent = $page->getSection()->handle;
if ($isPublic) {
$serviceData = [];
foreach ($page->modules->all() as $module) {
switch ($module->type->handle) {
case 'service':
$service = $module->service->one();
if ($service) {
$serviceData[] = [
'id' => $service->service->one()->id,
'title' => $service->service->one()->title,
];
}
break;
}
}
$coverColor = [
'r' => $page->coverColor ? $page->coverColor->r : 0,
'g' => $page->coverColor ? $page->coverColor->g : 0,
'b' =>$page->coverColor ? $page->coverColor->b : 0,
];
$caseStudies[] = [
'id' => $page->id,
'title' => $page->title,
'meta' => [
'navigationColor' => $page->navigationColor->value,
'title' => $page->metaTitle ? $page->metaTitle : $page->title,
'description' => $page->metaDescription,
],
'slug' => $page->slug,
'postDate' => date("d-m-Y",$page->postDate->getTimestamp()),
'json' => UrlHelper::url("work/{$page->slug}.json"),
'parent' => $parent,
'headline' => $page->headline,
'client' => $parent === 'caseStudies' ? $page->client->one()->title : null,
'services' => $serviceData,
'discipline' => array_map(function (CategoryModel $category) {
return [
'id' => $category->id,
'title' => $category->title,
];
}, $page->discipline->find()),
'cover' => handelImages($page->cover->all()),
'coverColor' => $coverColor,
'coverVideo' => [
'source' => $page->coverVideo
]
];
}
}
return $caseStudies;
}
Everything works except in the caseStudies array I have added this line:
'discipline' => array_map(function (CategoryModel $category) {
return [
'id' => $category->id,
'title' => $category->title,
];
}, $page->discipline->find()),
which returns the error: Argument 1 passed to {closure}() must be an instance of CategoryModel, instance of craft\elements\Category given
site is at Craft 3.3.15. Element-Api plugin is 2.6.0
'dispiplines' => array_map('strval', $page->discipline->all())
This worked. Found a tag example right on the github page https://github.com/craftcms/element-api

Uploading JSON file to MYSQL using Laravel not working

I am working on a script to upload a JSON file with all our COmpany data from our previous CRM system into a MYSQL database using laravel and i am running into an issue will parsing the json data. I have converted it to an array and run a foreach to upload each company, but it is throwing an error saying it cant convert from array to string. Im unsure what i am doing wrong here, my code is below as well as one company (all are very similar):
public function uploadCompanies()
{
$json = File::get("database/data/accounts.json");
$data = json_decode($json);
foreach($data as $item) {
DB::table('ucustomers')->insert(
[
'dynamics_guid' => $item->accountid,
'customer_code' => $item->mc_unleashedcode,
'customer_name' => $item->name,
'phone_number' => $item->telephone1,
'fax_number' => $item->fax,
'email' => $item->emailaddress1,
'website' => $item->websiteurl,
'override_reps' => [],
'updated_at' => date('Y-m-d H:i')
]
);
}
}
accounts.json
[
{
"#odata.etag": "W/\"145746454\"",
"name": "Core Pharmacy",
"opendeals": 0,
"modifiedon": "2020-08-29T14:11:19Z",
"address1_stateorprovince": "VIC",
"telephone1": "03 9338 1504",
"accountid": "5b46f158-d8ef-e911-a812-000d3a799888",
"websiteurl": null,
"mc_unleashedcode": "C1000096",
"fax": "03 9334 5030"
"emailaddress1": "tullamarine#locale.com.au",
}
]
ERROR
ErrorException
Array to string conversion
at vendor/laravel/framework/src/Illuminate/Support/Str.php:488
484|
485| $result = array_shift($segments);
486|
487| foreach ($segments as $segment) {
> 488| $result .= (array_shift($replace) ?? $search).$segment;
489| }
490|
491| return $result;
492| }
+8 vendor frames
9 app/Unleashed/DynamicsUpload.php:52
Illuminate\Database\Query\Builder::insert()
10 app/Console/Commands/InsertDynamicsData.php:41
App\Unleashed\DynamicsUpload::uploadCompanies()
Your problem is. you try to assign array to string when insert:
public function uploadCompanies()
{
$json = File::get("database/data/accounts.json");
$data = json_decode($json);
foreach($data as $item) {
DB::table('ucustomers')->insert(
[
'dynamics_guid' => $item->accountid,
'customer_code' => $item->mc_unleashedcode,
'customer_name' => $item->name,
'phone_number' => $item->telephone1,
'fax_number' => $item->fax,
'email' => $item->emailaddress1,
'website' => $item->websiteurl,
'override_reps' => [], // error on this one
'updated_at' => date('Y-m-d H:i')
]
);
}
}
there are 2 solution to fixed it.
if you want to insert array to table direct you need to encode it like below:
public function uploadCompanies()
{
$json = File::get("database/data/accounts.json");
$data = json_decode($json);
foreach($data as $item) {
DB::table('ucustomers')->insert(
[
'dynamics_guid' => $item->accountid,
'customer_code' => $item->mc_unleashedcode,
'customer_name' => $item->name,
'phone_number' => $item->telephone1,
'fax_number' => $item->fax,
'email' => $item->emailaddress1,
'website' => $item->websiteurl,
'override_reps' => json_encode([]), // need to encode first
'updated_at' => date('Y-m-d H:i')
]
);
}
}
solution 2 is using model for create:
but first you need to cast override_reps field to array. so laravel will handle it for you
// assume you model name Customer
class Customer extends Model
{
protected $casts =[
'override_reps'=>'array',
];
}
// on controller
public function uploadCompanies()
{
$json = File::get("database/data/accounts.json");
$data = json_decode($json);
foreach($data as $item) {
Customer::create(
[
'dynamics_guid' => $item->accountid,
'customer_code' => $item->mc_unleashedcode,
'customer_name' => $item->name,
'phone_number' => $item->telephone1,
'fax_number' => $item->fax,
'email' => $item->emailaddress1,
'website' => $item->websiteurl,
'override_reps' => [],//lavavel model will encode it before insert
'updated_at' => date('Y-m-d H:i')
]
);
}
}

Search into non symetrical multidimensional array with PHP

I have found a lot of question and some great answers in order to search into an array with PHP. But everytime, the script answered too perfectly to the quesiton, and not globaly OR all arrays are symetricals.
My Array can look like this:
$data = [
'steve' => [
'id' => [
'#text' => 1,
],
'pseudo' => [
'#text' => 'LOL'
],
],
'albert' => [
'id' => [
'#text' => 2,
],
'pseudo' => [
'#text' => 'KILLER'
],
],
'john' => [
'id' => [
'#text' => 3,
],
'pseudo' => [
'#text' => 'NOOBS'
],
],
];
Which mean that my Array can look beautifully symetrically generated, or completely messy and with random subarray.
My aim is to search inside and found the PSEUDO of AN ID. And unfortunately, I can't change the webservice which give me this result.
I had tried with array_column or array_search, but the only thing I had successfully returned is if it founds something, or not. But can't identify it. And my script was very slow.
Something like :
search($array, 2); //which return KILLER
or more optionable maybe?
My Array can have a lot of IDs (100+). So I'm trying to found something optimize. :/
There's probably a million ways to do this, but ultimately you'll need some recursive approach that's able to filter on the value and the path to that value. For this, the following would be one of those million ways.
It uses the predefined iterators:
CallbackFilterIterator
RecursiveIteratorIterator
RecursiveArrayIterator
in combination with a custom PathAsKeyDecorator iterator.
Demo here
<?php
declare(strict_types=1);
final class PathAsKeyDecorator implements \Iterator
{
private RecursiveIteratorIterator $inner;
public function __construct(RecursiveIteratorIterator $inner)
{
$this->inner = $inner;
}
public function current()
{
return $this->inner->current();
}
public function next(): void
{
$this->inner->next();
}
public function key()
{
$path = [];
for ($i = 0, $depth = $this->inner->getDepth(); $i <= $depth; $i++) {
$path[] = $this->inner->getSubIterator($i)->key();
}
return $path;
}
public function valid(): bool
{
return $this->inner->valid();
}
public function rewind(): void
{
$this->inner->rewind();
}
}
$input = [
'steve' => [
'id' => [
'#text' => 1,
],
],
'albert' => [
'id' => [
'#text' => 2,
],
],
'john' => [
'profil' => [
'id' => [
'#text' => 3,
],
],
],
];
// this is the filter function that should be customized given your requirements
// or create a factory function which produces these types of filter functions
$filter = static function ($current, array $path): bool {
// with help from the PathAsKeyDecorator
// we can decide on the path to the current value
return ['id', '#text'] === array_slice($path, -2)
// and the current value
&& 2 === $current;
};
// configure the iterator
$it = new CallbackFilterIterator(
new PathAsKeyDecorator(new RecursiveIteratorIterator(new RecursiveArrayIterator($input))),
$filter,
);
// traverse the iterator
foreach ($it as $path => $val) {
print_r([
'path' => $path,
'val' => $val
]);
}
An alternative approach could be one with simple functions, like:
Demo here
<?php
declare(strict_types=1);
function iterateWithPath(iterable $input, array $path = []): iterable {
foreach ($input as $key => $value) {
$pathToHere = [...$path, $key];
is_iterable($value)
? yield from iterateWithPath($value, $pathToHere)
: yield $pathToHere => $value;
}
}
function filterIterable(iterable $it, callable $filter): iterable {
foreach ($it as $key => $value) {
if ($filter($value, $key)) {
yield $key => $value;
}
}
}
$input = [
'steve' => [
'id' => [
'#text' => 1,
],
],
'albert' => [
'id' => [
'#text' => 2,
],
],
'john' => [
'profil' => [
'id' => [
'#text' => 3,
],
],
],
];
$it = filterIterable(iterateWithPath($input), static function ($current, array $path): bool {
return ['id', '#text'] === array_slice($path, -2)
&& 2 === $current;
});
foreach ($it as $path => $val) {
print_r([
'path' => $path,
'val' => $val
]);
}
complete edit cause of structure change of the array. the json_encode is used for changing the array to a string. Only does its job when there is in every array slice an id and an pseudo.
$data = [
'steve' => [
'id' => [
'#text' => 1,
],
'pseudo' => [
'#text' => 'LOL'
],
],
'albert' => [
'id' => [
'#text' => 2,
],
'pseudo' => [
'#text' => 'KILLER'
],
],
'john' => [
'id' => [
'#text' => 3,
],
'pseudo' => [
'#text' => 'NOOBS'
],
],
];
$data = json_encode($data, JSON_NUMERIC_CHECK);
preg_match_all('~"id":{"#text":([^{]*)}~i', $data, $ids);
preg_match_all('~"pseudo":{"#text":"([^{]*)"}~i', $data, $pseudos);
$lnCounter = 0;
$laResult = array();
foreach($ids[1] as $lnId) {
$laResult[$lnId] = $pseudos[1][$lnCounter];
$lnCounter++;
}
echo $laResult[2];
results in KILLER

Array Operations to add / remove entries from 1 to another

I have 2 sets of array:
Data:
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => [
'S-2',
'S-3',
'S-5',
],
],
];
Source (from database):
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
What I need to achieve:
If a supplier code is missing in $data but exists in $database,
remove it from $database.
If a supplier code exists in $data but missing in $database, add it into $database
The output of the example here should be as follows:
$output = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-5',
]
],
];
I was thinking of removing the suppliers subarray, then reconstruct the structure based on the data from supplier_codes. But the problem is some of the entries in suppliers may have an optional field called reference.
Try this
<?php
$data = [
[
'company_code' => 'ABC',
'supplier_codes' => ['S-2','S-3','S-5'],
],
];
$database = [
'company_code' => 'ABC',
'suppliers' => [
[
'code' => 'S-1',
],
[
'code' => 'S-2',
'reference' => '12345'
],
[
'code' => 'S-3',
],
[
'code' => 'S-4',
'reference' => 'some string',
]
],
];
foreach($database['suppliers'] as $k=>$v){
foreach($data as $kd=>$vd){
$valueremove = false;
$removeIndex = '';
foreach($vd['supplier_codes'] as $key=>$val){
if($val == $v['code']){
$valueremove = false;
$removeIndex = '';
break;
} else {
$valueremove = true;
$removeIndex = $k;
}
}
if($valueremove == true){
unset($database['suppliers'][$removeIndex]);
} else {
$valueinsert = false;
foreach($data as $kd=>$vd){
foreach($vd['supplier_codes'] as $key=>$val){
foreach($database['suppliers'] as $kc=>$vc){
if($val == $vc['code']){
$valueinsert = false;
$insertIndex = '';
$insertVal = '';
break;
} else {
$valueinsert = true;
$insertIndex = count($database['suppliers'])+1;
$insertVal = $val;
}
}
if($valueinsert == true){
$database['suppliers'][$insertIndex] = array('code'=>$insertVal);
}
}
}
}
}
}
echo "<PRE>"; print_r($database);
I end up solving my problem this way:
$result = $database;
$result['suppliers'] = [];
foreach($data as $tag) {
foreach($tag['supplier_codes'] as $code) {
$found = false;
foreach($database['suppliers'] as $supplier) {
if($supplier['code'] === $code) {
$result['suppliers'][] = $supplier;
$found = true;
}
}
if(!$found) {
$result['suppliers'][] = ['code' => $code];
}
}
}
Output of print_r($result);:
Array
(
[company_code] => ABC
[suppliers] => Array
(
[0] => Array
(
[code] => S-2
[reference] => 12345
)
[1] => Array
(
[code] => S-3
)
[2] => Array
(
[code] => S-5
)
)
)

Laravel Table Filter

So I have website based on Laravel framework. I have table and the filter for table to filter the items - http://prntscr.com/ccht0f.
When I filter them by anything all works good, but when I change the page filtering disapers from session. http://prntscr.com/cchutt - http://prntscr.com/cchuyo. Looks like pagination destroys all sessions.
My code:
public function filters(Request $request)
{
$filter_item_acquisition_forms = [null];
$filter_collections = [null];
$filter_origin_dates = [null];
$order_by = request()->query('order_by', 'id');
$dir = request()->query('dir', 'desc');
$storage_items = StorageItem::with(
'authorClassification',
'placeClassification',
'classificationValueOrigin',
'classificationValueOriginDate',
'classificationValueItemAcquisitionForm',
'classificationValueCollection',
'classificationValuesMaterials',
'classificationValuesTechnique',
'employeeClassificationsRestorers',
'userLastUpdatedBy.employeeClassification',
'userResponsibleUser.employeeClassification',
'attachments'
);
$storage_items = $storage_items->id($request->filter_id)
->acceptanceId($request->filter_acceptance_id)
->acceptanceNumber($request->filter_acceptance_number)
->acceptanceDate($request->filter_acceptance_date)
->mainInventoryNumber($request->filter_main_inventory_number_from, $request->filter_main_inventory_number_to)
->scientificInventoryNumber($request->filter_scientific_inventory_number)
->imageInventoryNumber($request->filter_image_inventory_number)
->itemCosts($request->filter_item_costs_from, $request->filter_item_costs_to)
->originDate($request->filter_origin_date)
->updatedAt($request->filter_updated_at_from, $request->filter_updated_at_to)
->addingDate($request->filter_added_from, $request->filter_added_to)
->itemAcquisitionForm($request->filter_item_acquisition_form)
->collection($request->filter_collection)
->employee($request->filter_employee)
->isInExposition($request->filter_is_in_exposition)
->isRestored($request->filter_is_restored)
->haveAttachments($request->filter_have_attachments)
->haveNotCosts($request->filter_have_not_costs)
->searchInField($request->filter_search_in_field, $request->filter_word_or_phrase);
$storage_items = $storage_items->orderBy($order_by, $dir)->paginate(20);
foreach ($storage_items as $storage_item) {
if ($storage_item->classificationValueItemAcquisitionForm != null) {
$filter_item_acquisition_forms[$storage_item->classificationValueItemAcquisitionForm->id] = $storage_item->classificationValueItemAcquisitionForm->value;
}
if ($storage_item->classificationValueCollection != null) {
$filter_collections[$storage_item->classificationValueCollection->id] = $storage_item->classificationValueCollection->value;
}
if (!is_null($storage_item->classificationValueOriginDate)) {
$filter_origin_date[$storage_item->classificationValueOriginDate->id] = $storage_item->classificationValueOriginDate->value;
}
}
$request->flash();
return view('panel.storage_items.filters')->with([
'storage_items' => $storage_items,
'current_order_query' => compact('order_by', 'dir'),
'employees' => [null] + EmployeeClassification::lists('employee', 'id')->toArray(),
'filter_what_to_look_for' => [
'storage-items' => trans('fields.storage_items'),
'storage-item-acceptances' => trans('fields.storage_items_acceptances'),
'archive-objects' => trans('fields.archive_objects'),
'archive-documents' => trans('fields.archive_documents'),
'archive-docs-acceptance-acts' => trans('fields.archive_documents_acceptance_acts')
],
'filter_item_acquisition_forms' => $filter_item_acquisition_forms,
'filter_collections' => [null] + Classification::findOrFail(2)->classificationValues()->lists('value', 'id')->toArray(),
//'filter_collections' => $filter_collections,
'filter_origin_dates' => $filter_origin_dates,
'filter_search_in_field' => [
trans('fields.storage_items') => [
'item_name' => trans('fields.item_name'),
'author' => trans('fields.author'),
'about_the_author' => trans('fields.about_author'),
'item_description' => trans('fields.item_description'),
'content_description' => trans('fields.content_description'),
'item_history' => trans('fields.item_history'),
'branding_notes' => trans('fields.branding_notes'),
'damage_characteristics' => trans('fields.damage_characteristics'),
'published' => trans('fields.published'),
'exhibited' => trans('fields.exhibited'),
'inquiries' => trans('fields.inquiries')
],
trans_choice('fields.attachments', 0) => [
'attachment_name' => trans('fields.name'),
'attachment_description' => trans('fields.description')
]
]
]);
}
So I fixed it myself.
Solution:
I got the collection ID from request and stored it in variable.
$filter_collection = $request->filter_collection;
Passed variable to the view
->with('filter_collection', $filter_collection)
And changed my pagination to pass collection ID to next page
{{ $storage_items->appends(['filter_collection' => $filter_collection])->links() }}

Categories