Entity field ArrayCollection, doctrine insert name class in database - doctrine

I have a object with field type array, it's initialize to docrine collection, but when I save the objcet, the value inserted into my database is :
O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollection elements";a:2:{i:0;i:1;i:1;i:2;}}
When I dump after the form submit
if ($form->isSubmitted() && $form->isValid()) {
the value seems correct
-days: ArrayCollection {#14714 ▼
-elements: array:2 [▼
0 => 1
1 => 2
]
My entity field
/**
* #var ArrayCollection
* #ORM\Column(type="array")
*/
private $days;
public function __construct()
{
$this->days = new ArrayCollection();
$this->end_time = new \DateTime();
}
public function addDay(int $day): self
{
if (!$this->days->contains($day)) {
$this->days[] = $day;
}
return $this;
}
public function removeDay(int $day): self
{
if ($this->days->contains($day)) {
$this->days->removeElement($day);
}
return $this;
}
/**
* #return Collection|array
*/
public function getDays(): Collection
{
return $this->days;
}
Thank you

Related

Eloquent relationship returning all when ID doesn't match

For some reason my relationship is fetching all from the corresponding table when I dump it, however dumping the result does not show these rows.
The slider ID does not match the slider_id within the settings table.
So the following works fine, as expected the settings is an empty array:
/**
* #return HasOne
*/
public function slider(): HasOne
{
return $this->hasOne(Slider::class)->withDefault(
(new Slider())->attributesToArray()
);
}
Result:
{
"name": "media-slider",
"settings": []
}
However when I dump within the attribute I get all the rows from the settings table, when this query should be getting all settings where the slider_id matches the current slider, which has a different ID.
<?php
namespace App\Models\Media;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
class Slider extends Model
{
/** #var string[] */
protected $appends = [ 'settings' ];
protected $defaults = [
'test' => [
'id' => 0,
'name' => 'default name',
]
];
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->attributes = $this->defaults['test'];
}
/**
* #return HasMany
*/
public function settings(): HasMany
{
return $this->hasMany(SliderSetting::class);
}
/**
* Get the slider settings, extract the value and key by the key, also
* group if multiple setting groups are required.
*
* Perform this logic here so data can be used directly by the JavaScript.
*
* #return \Illuminate\Database\Eloquent\Collection|Collection
*/
public function getSettingsAttribute()
{
dd($this->settings()->get()); // This should be empty!
return $this->settings()->get()
->groupBy('group')
->map(static function ($group) {
$group = $group->keyBy('key');
return $group->map(static function ($setting) {
return $setting->getAttribute('value');
});
});
}
}
Edit
/**
* #return HasMany
*/
public function sliderSettings(): HasMany
{
dd($this->hasMany(SliderSetting::class)->toSql());
return $this->hasMany(SliderSetting::class);
}
The above outputs:
select * from slider_settings
Shouldn't it be the following?
select * from slider_settings where slider_settings.slider_id = ?

Laravel Importing to Excel , error when passing a variable

I want to import some categories, but what i need is also the parent category id.
public function importCategory(Request $request, $cat_id){
$import = new CategoryImport($cat_id);
$import->import($request->file);
if ($import->failures()->count() > 0) {
$message = '';
foreach ($import->failures() as $failure) {
$failure->row(); // row that went wrong
$failure->attribute(); // either heading key (if using heading row concern) or column index
$failure->errors(); // Actual error messages from Laravel validator
$failure->values(); // The values of the row that has failed.
}
return redirect()->back();
} else {
return redirect()->back()->with('success', sprintf('Success'));
}
}
Here is the CategoryImport.php
class CategoryImport implements WithHeadingRow, WithValidation, SkipsOnFailure,OnEachRow
{
use Importable, SkipsFailures;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
protected $cat_id = null;
public function __construct( $cat_id) {
$category_id = $cat_id;
}
public function onRow(Row $row)
{
$row=$row->toArray();
Category::create([
'name' => $row['name'],
'image' => $row['image'],
'business_category_id' => $this->category_id,
]);
}
}
So here is the error, it says undefined property, and i am trying to figure it out but don't understand.
Undefined property: App\Imports\CategoryImport::$category_id
Inside the constructor you need to assign the correct variable.
class CategoryImport implements WithHeadingRow, WithValidation, SkipsOnFailure,OnEachRow
{
use Importable, SkipsFailures;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
protected $cat_id = null;
public function __construct($cat_id) {
$this->cat_id = $cat_id;
}
I think the line 'business_category_id' => $this->category_id is wrong. You need to use
'business_category_id' => $this->cat_id
because that is the variable you assign in the constructor.
You didn't set cat_id properly. In your CategoryImport you should have :
protected $category_id = null;
public function __construct($cat_id) {
$$this->category_id = $cat_id;
}

Laravel Virgin: Setting up and destroying database in phpunit integration tests

Using the nilportuguess' eloquent repository library, I made the following (with bugs) repository:
namespace App\Repositories;
use NilPortugues\Foundation\Infrastructure\Model\Repository\Eloquent\EloquentRepository;
use App\Model\Rover;
class RoverRepository extends EloquentRepository
{
/**
* {#inheritdoc}
*/
protected function modelClassName()
{
return Rover::class;
}
/**
* {#inheritdoc}
*/
public function find(Identity $id, Fields $fields = null)
{
$eloquentModel = parent::find($id, $fields);
return $eloquentModel->toArray();
}
/**
* {#inheritdoc}
*/
public function findBy(Filter $filter = null, Sort $sort = null, Fields $fields = null)
{
$eloquentModelArray = parent::findBy($filter, $sort, $fields);
return $this->fromEloquentArray($eloquentModelArray);
}
/**
* {#inheritdoc}
*/
public function findAll(Pageable $pageable = null)
{
$page = parent::findAll($pageable);
return new Page(
$this->fromEloquentArray($page->content()),
$page->totalElements(),
$page->pageNumber(),
$page->totalPages(),
$page->sortings(),
$page->filters(),
$page->fields()
);
}
/**
* #param array $eloquentModelArray
* #return array
*/
protected function fromEloquentArray(array $eloquentModelArray) :array
{
$results = [];
foreach ($eloquentModelArray as $eloquentModel) {
//This is required to handle findAll returning array, not objects.
$eloquentModel = (object) $eloquentModel;
$results[] = $eloquentModel->attributesToArray();
}
return $results;
}
}
And In order to locate them I thought to make an Integration test on an sqlite inmemory db:
namespace Test\Database\Integration\Repositories;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Repositories\RoverRepository;
use App\Model\Rover;
use App\Model\Grid;
class RoverRepositoryTest extends TestCase
{
use RefreshDatabase;
private $repository=null;
public function setUp(): void
{
parent::setUp();
$grid=factory(Grid::class)->create([
'width'=>5,
'height'=>5
]);
$rover=factory(Rover::class, 5)->create([
'grid_id' => $grid->id,
'grid_pos_x' => rand(0, $grid->width),
'grid_pos_y' => rand(0, $grid->height),
]);
//How do I run Migrations and generate the db?
$this->repository = new RoverRepository();
}
public function tearDown(): void
{
parent::tearDown();
//How I truncate and destroy Database?
}
/**
* Testing Base Search
*
* #return void
*/
public function testBasicSearch(): void
{
//Some Db test
}
}
But I have some questions:
How do I save the generated via factory Models?
How do I nuke my database in tearDown()?

Extra data on a collection operation

Does anybody know how to add extra data on a collection?
The doc says much about how to add extra data on an item which translates into decorating the ItemNormalizer service, and it works pretty well.
But I’m struggling in finding out which normalizer to decorate when it comes to add some data on a collection of entities. The extra data could be anything: the current user logged in, a detailed pager, some debug parameters, ... that are not related to a specific entity, but rather on the request itself.
The only working solution for now is to hook on a Kernel event but that's definitely not the code I like to write:
use ApiPlatform\Core\EventListener\EventPriorities;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final class SerializeListener implements EventSubscriberInterface
{
/**
* #var Security
*/
private $security;
/**
* #var NormalizerInterface
*/
private $normalizer;
public function __construct(
Security $security,
NormalizerInterface $normalizer
) {
$this->security = $security;
$this->normalizer = $normalizer;
}
public function addCurrentUser(GetResponseForControllerResultEvent $event)
{
$request = $event->getRequest();
if ($request->attributes->has('_api_respond')) {
$serialized = $event->getControllerResult();
$data = json_decode($serialized, true);
$data['hydra:user'] = $this->normalizer->normalize(
$this->security->getUser(),
$request->attributes->get('_format'),
$request->attributes->get('_api_normalization_context')
);
$event->setControllerResult(json_encode($data));
}
}
/**
* #inheritDoc
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => [
'addCurrentUser',
EventPriorities::POST_SERIALIZE,
],
];
}
}
Any ideas?
Thank you,
Ben
Alright, I finally managed to do this.
namespace App\Api;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final class ApiCollectionNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
/**
* #var NormalizerInterface|NormalizerAwareInterface
*/
private $decorated;
public function __construct(NormalizerInterface $decorated)
{
if (!$decorated instanceof NormalizerAwareInterface) {
throw new \InvalidArgumentException(
sprintf('The decorated normalizer must implement the %s.', NormalizerAwareInterface::class)
);
}
$this->decorated = $decorated;
}
/**
* #inheritdoc
*/
public function normalize($object, $format = null, array $context = [])
{
$data = $this->decorated->normalize($object, $format, $context);
if ('collection' === $context['operation_type'] && 'get' === $context['collection_operation_name']) {
$data['hydra:meta'] = ['foo' => 'bar'];
}
return $data;
}
/**
* #inheritdoc
*/
public function supportsNormalization($data, $format = null)
{
return $this->decorated->supportsNormalization($data, $format);
}
/**
* #inheritdoc
*/
public function setNormalizer(NormalizerInterface $normalizer)
{
$this->decorated->setNormalizer($normalizer);
}
}
# config/services.yaml
services:
App\Api\ApiCollectionNormalizer:
decorates: 'api_platform.hydra.normalizer.collection'
arguments: [ '#App\Api\ApiCollectionNormalizer.inner' ]
Keep it for the records :)

laravel 4 - inserting of multiple fields in array

The following function in laravel stores my form input. I can't get it to store anything other than the author id and the title. It just won't store the keywords.
Below is the function in my Postcontroller.php
public function store()
{
$input = Input::all();
$rules = array(
'title' => 'required',
'text' => 'required',
);
$validation = Validator::make($input, $rules);
if ($validation->fails()) {
return Redirect::back()->withErrors($validation)->withInput();
} else {
// create new Post instance
$post = Post::create(array(
'title' => $input['title'],
'keywords' => $input['keywords'],
));
// create Text instance w/ text body
$text = Text::create(array('text' => $input['text']));
// save new Text and associate w/ new post
$post->text()->save($text);
if (isset($input['tags'])) {
foreach ($input['tags'] as $tagId) {
$tag = Tag::find($tagId);
$post->tags()->save($tag);
}
}
// associate the post with user
$post->author()->associate(Auth::user())->save();
return Redirect::to('question/'.$post->id);
}
}
Post.php (model)
<?php
class Post extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'posts';
/**
* Whitelisted model properties for mass assignment.
*
* #var array
*/
protected $fillable = array('title');
/**
* Defines a one-to-one relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-one
*/
public function text()
{
return $this->hasOne('Text');
}
/**
* Defines an inverse one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function author()
{
return $this->belongsTo('User', 'author_id');
}
/**
* Defines a many-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#many-to-many
*/
public function tags()
{
return $this->belongsToMany('Tag');
}
/**
* Defines an inverse one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function category()
{
return $this->belongsTo('Category');
}
/**
* Defines a polymorphic one-to-one relationship.
*
* #see http://laravel.com/docs/eloquent#polymorphic-relations
*/
public function image()
{
return $this->morphOne('Image', 'imageable');
}
/**
* Defines a one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function comments()
{
return $this->hasMany('Comment');
}
}
You are stopping the mass assignment of keywords with your model settings.
Change
protected $fillable = array('title');
to
protected $fillable = array('title', 'keywords');

Resources