I have this Model where I'm calling with
$data = ProcessoSeletivoRDSincroniza::all();
This model gaves me a collection with more than 300 records, with attributes like name, celphone, email etc..
And I have to pass this collection to a API body request, by an array, this array has specific key fields, and the only way that I think about doing this its iterating this collection with a foreach loop, and creating/setting this array with this collection fields, and works ok, but my application does one request for every record, and this is not a good way to handle it.
So I'm thinking if's there a way to create an "custom" and single array with all that records, so I dont need to iterate and make a request by record, and just tranform all this records in a JSON file and send it.
This is my code now:
$data = ProcessoSeletivoRDSincroniza::all();
//$data = $data->toArray();
$api = new RDStationApi();
foreach($data as $row)
{
$events = array(
"event_type" => "CONVERSION",
"event_family" => "CDP",
"payload" => [
"conversion_identifier" => "Name of the conversion event",
"name" => $row->nome_completo,
"email" => $row->email,
"personal_phone" => $row->telefone,
"cf_ps_curso" => $row->ps_curso,
"cf_ps_ano_semestre" => $row->ps_anosemestre,
"cf_ps_data_vestibular_agendado" => $row->ps_data_vestibular_agendado,
"cf_ps_nota_enem" => (string) $row->ps_nota_enem,
"cf_forma_ingresso" => $row->ps_forma_ingresso,
"cf_ps_unidade" => $row->ps_unidade,
"cf_ps_situacao" => $row->ps_situacao
]
);
$return = $api->update_contact($events);
You can use a Laravel functionality called API-Resources.
https://laravel.com/docs/8.x/eloquent-resources
Create a new Resource for your Model:
php artisan make:resource ProcessoSeletivoRDSincronizaResource
Afterwards this will create a file in the Resource folder named; ProcessoSeletivoRDSincronizaResource , in this file you will need to adapt the toArray() method.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProcessoSeletivoRDSincronizaResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
//ADD ALL THE FIELDS, methods also work normally: $this->myMethod()
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Afterwards you can use the Resource like this:
//for the whole collection
$events = ProcessoSeletivoRDSincronizaResource::collection(ProcessoSeletivoRDSincroniza::all());
//or for single use
$event = new ProcessoSeletivoRDSincronizaResource($single_model)
Related
I'm using RESTClient to send the http request to the backend:
restclient.net
Currently, my JSON looks like this:
[
{"title":"my blogADD","description":"myblogdescriptionADD","status":1},
{"title":"my blogUPDATEDADD","description":"myblogdescriptionUPDATEDADD","status":1},
{"title":"my blog33","description":"myblogdescription33ADD","status":1}
]
The table in the DB looks like this, its name is "articles":
https://imgur.com/onXEgzg
The function inside the controller responsible to insert the data looks like this:
public function create(Request $request){
$this->validate($request, [
'title' => 'required',
'description' => 'required'
]);
//insert record
$article = Article::create($request->all());
return response()->json($article, 201);
}
So far, when I send the request, the data doesn't get inserted.
The header is set to content-type:application/json
inserting a single record works.
Sending the above array of objects doesn't do anything, it doesn't even throw an error.
I already read somewhere that one might use the id as key to identify each object inside the array. But is that really the problem here?
The ID of the table is already the PK and its set to AUTO_INCREMENT, so at least technically assigning an ID manually shouldnt be necessary, although of course the order of the inserted might differ from the order they arrived inside the inputted array.
So what am I missing?
I am pretty new to Lumen, and I'm just learning to use the model.
The controller code stems from a tutorial video:
https://www.youtube.com/watch?v=6Oxfb_HNY0U
I must admit that I don't really understand what the
$request->all()
inside
$article = Article::create($request->all());
does.
When reading the official laravelDOC, I found this syntax to save records to the DB
https://laravel.com/docs/5.8/eloquent
<?php
namespace App\Http\Controllers;
use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class FlightController extends Controller
{
/**
* Create a new flight instance.
*
* #param Request $request
* #return Response
*/
public function store(Request $request)
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
}
and it differs quite a lot from what I have, so I wonder how my syntax actually worx xD
EDIT:
Here is the debugging result of $request->all()
^ array:3 [
0 => array:3 [
"title" => "my blogADD"
"description" => "myblogdescriptionADD"
"status" => 1
]
1 => array:3 [
"title" => "my blogUPDATEDADD"
"description" => "myblogdescriptionUPDATEDADD"
"status" => 1
]
2 => array:3 [
"title" => "my blog33"
"description" => "myblogdescription33ADD"
"status" => 1
]
]
See The API:
https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Builder.html#method_create
create is only save a new model and return the instance.
https://laravel.com/api/5.8/Illuminate/Database/Query/Builder.html#method_insert
Use insert instead of create
Article::insert($request->all());
I'm pretty new to Phpspec testing and I don't know what is the correct way to test multiple scenarios when transforming a object to different response structure.
I need to check if price is correctly calculated. Here I have the Transformer spec test:
/**
* #dataProvider pricesProvider
*/
public function it_should_check_whether_the_prices_are_correct(
$priceWithoutVat,
$priceWithVat,
$vat,
Request $request,
Repository $repository
) {
$productIds = array(100001);
$result = array(
new Product(
'100001',
'MONSTER',
new Price(
$priceWithoutVat,
20,
'GBP',
null,
null
)
)
);
$expected = array(
array(
"productId" => "100001",
"brand" => "MONSTER",
"price" => array(
"amount" => $priceWithVat,
"vatAmount" => $vat,
"currencyCode" => "GBP",
"discountAmount" => (int)0
)
)
);
$repository->getResult(array(
Repository::FILTER_IDS => $productIds
))->willReturn($result);
$request->get('productIds')->willReturn(productIds);
/** #var SubjectSpec $transformedData */
$transformedData = $this->transform($request);
$transformedData->shouldEqual($expected);
}
public function pricesProvider()
{
return array(
array('123.456789', 14814, 2469),
array('60.00', 7200, 1200),
);
}
In my Transformer class I have a function which formats data to the correct format:
public function transform(Request $request)
{
$productIds = $request->get('productIds');
$productsResult = $this->repository->getResult(array(
Repository::FILTER_IDS => $productIds
));
$products = array();
foreach ($productsResult as $product) {
$products[] = $this->formatData($product);
}
return $products;
}
/**
* #param Product $product
* #return array
*/
private function formatData(Product $product)
{
return array(
'productId' => $product->getId(),
'brand' => $product->getBrandName(),
'price' => array(
'amount' => (int)bcmul($product->getPrice()->getAmountWithTax(), '100'),
'vatAmount' => (int)bcmul($product->getPrice()->getTaxAmount(), '100'),
'currencyCode' => $product->getPrice()->getCurrencyCode(),
'discountAmount' => (int)bcmul($product->getPrice()->getDiscountAmount(), '100')
)
);
}
The problem is, that I'm getting this error message:
316 - it should check whether the prices are correct
warning: bcmul() expects parameter 1 to be string, object given in
/src/AppBundle/Database/Entity/Product/Price/Price.php line 49
If I hard-code those values then the test is green. However I want to test varios prices and results, so I decided to use the dataProvider method.
But when dataProvider passes the $amountWithoutTax value, it's not string but PhpSpec\Wrapper\Collaborator class and because of this the bcmul fails.
If I change the $amountWithoutTax value to $priceWithoutVat->getWrappedObject() then Double\stdClass\P97 class is passed and because of this the bcmul fails.
How do I make this work? Is it some banality or did I completely misunderstood the concept of this?
I use https://github.com/coduo/phpspec-data-provider-extension and in composer.json have the following:
"require-dev": {
"phpspec/phpspec": "2.5.8",
"coduo/phpspec-data-provider-extension": "^1.0"
}
If getAmountWithTax() in your formatData method returns an instance of PhpSpec\Wrapper\Collaborator, it means that it returns a Prophecy mock builder instead of the actual mock, i.e. the one that you get by calling reveal() method. I don't know how your data provider looks like, but it seems that you're mocking your Price value objects instead of creating real instances thereof, and $product->getPrice() in your production code returns the wrong kind of object.
The solution would be either to create a real instance of the Price value object that's later returned by $product->getPrice() with new in the data provider, or by calling reveal() on that instance, like this (assuming $price is a mock object that comes from a type hinted parameter):
$product->getPrice()->willReturn($price->reveal());
I'm learning Laravel and have created a public endpoint where I want to output only certain information of some comments if a user is not authenticated from a GET request.
I have managed to filter out the comments based on whether or not they are approved. I now want to filter out the data that is returned. I have attached a screenshot of what is currently returned.
Ideally, I only want to return the id, name and the body in the json. How can I go about this? I tried the pluck() method which did not give the desired results. Any pointers would be greatly appreciated
public function index(Request $request)
{
if (Auth::guard('api')->check()) {
return Comment::all();
} else {
$comments = Comment::where('approved', 1)->get();
return $comments->pluck('id','name','body');
}
}
To select the particular columns, you can pass columns name to get as
$comments = Comment::where('approved', 1) -> get(['id','name','body']);
You can use a transformer to map the incoming data to a sensible output based on the auth state. The following example comes from the Fractal lib:
<?php
use Acme\Model\Book;
use League\Fractal;
$books = Book::all();
$resource = new Fractal\Resource\Collection($books, function(Book $book) {
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
});
Ideally, you would create 2 classes that extend from Transformer and pass the correct one to the output.
If you want to pass the result as json respose
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return Response::json($comments);
If you want to pass the result as to blade
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return view('your_blade_name')->with('comments',$comments);
I'm using laravel and elasticsearch-php to index and store data to elastic, my problem is that elastisearch uses from dynamic mapping but I need to set my custom mapping. How can I use from my mapping?
Bellow is my code:
$client = \Elasticsearch\ClientBuilder::create()->build();
$mappingData = array(
'index' => 'promote_kmp',
'body' => array(
'mappings' => $resource->getMappingProperties()
)
);
$client->indices()->create($mappingData);
$params = [
'type' => 'resources',
'id' => uniqid(),
'body' => [
'id' => $resource->id,
'name' => $resource->name,
'display_name_en' => $resource->display_name_en,
'display_name_pr' => $resource->display_name_pr,
'display_name_pa' => $resource->display_name_pa,
'table_name' => $resource->table_name,
'model_name' => $resource->model_name,
'in_sidemenu' => $resource->in_sidemenu,
'icon_class' => $resource->icon_class,
'created_at' => $resource->created_at,
'created_by' => $user,
]
];
//$response = $client->indices()->create($resource->getMappingProperties());
$client->index($params);
$resource->getMappingProperties() get the mapping array I have set in model.
but when I want to index a record it says IndexAlreadyExistsException[[promote_kmp] already exists]. This question arise when I want to search for date field searching is not properly working and I guess that mapping is not true.
As I was saying in comments.
The code is executing the creation of index every time you want to query.
But the index must be created only once.
So it should work like the migration for the DB's.
The only idea I can give you is to make a command to generate the index.
So that you could just
$ artisan elasticsearch:generate <index>
About the code, what I've done for our case, made the index with a way to inject the types, plus a way to create them into elasticsearch:
interface Index {
/**
* #param Type[] $types Index types (resources)
*/
function setTypes(array $types);
/**
* Generate the index and the types into the elasticsearch
*/
function create();
}
Then the types should generate the mappings and the type name (as /<index>/<type>, like:
interface Type {
/**
* #return string The type name
*/
function getName();
/**
* #return array The type mapping
*/
function getMapping();
}
So (somewhere), you would create the class (this could be better):
$myIndex = new MyIndex();
$myIndex->setTypes([
new MyFirstType(),
new MySecondType(),
//...
]);
$myIndex->create();
I hope this helps.
Code
Entry::updateOrCreate([
'intern_id'=>$intern['id'],
'created_at'=>Carbon::parse($input['date'])
],[
'company_id'=>$intern['supervisor']['company']['id'],
'content'=>$input['text']
]);
I'm using this code to try updating/creating a new record. It's suppose to matche intern_id and create_at column first. If found, then it creates a new one. However, it seems like it is always creating a new one and when it creates a new one, the company_id and intern_id column is set to 0 instead of the original value.
Note: intern_id or created_at are not PK columns.
Note2: created_at is a Date type, not DateTime
Use this code
Entry::updateOrCreate(['intern_id'=>$intern['id']],
[
'created_at'=>Carbon::parse($input['date']),
'company_id'=> $intern['supervisor']['company']['id'],
'content'=>$input['text']
]);
I believe this will work.
updateOrCreate() function of Model Abstract Class takes 2 parameters, but your parameter passing is breaking.
/**
* Create or update a record matching the attributes, and fill it with values.
*
* #param array $attributes
* #param array $values
* #return static
*/
public static function updateOrCreate(array $attributes, array $values = array())
{
$instance = static::firstOrNew($attributes);
$instance->fill($values)->save();
return $instance;
}
Entry::updateOrCreate(
[
'intern_id' => $intern['id'],
],
[
'created_at' => Carbon::parse($input['date'])
'company_id' => $intern['supervisor']['company']['id'],
'content' => $input['text']
]
);
because first argument array searched for first time
found one line with date and second line found other date deferent
-----------
// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
);
I had the same issue where it was only creating a record but it wasn't being updated in the event that the record exists.
The issue is that to allow for the mass assignment on the update you need to add the fields to be updated as fillable in your model.
In your Entry model you can have something close to this :
protected $fillable = [
'company_id',
'content',
];
I hope this helps in sorting out the issue.