Laravel Virgin: Access inverse model relationship in a model's mutator that participate in the relationship - database

In my logic I have these tables:
Table Grid:
id PK
width INT
height INT
Table Rover:
id pk
grid_pos_x UNSIGNED INT
grid_pos_y UNSIGNED INT
grid_id UNSINGED BIGINT
NOTE: I kept minimal in order to be more explanatory, for full table specs look on migration scripts below.
And I use the following migration script to create the schemas:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateGridTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('grid', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('width');
$table->unsignedInteger('height');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('grid');
}
}
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRoverTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('rover', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('grid_id')->unsigned();
$table->string('command');
$table->foreign('grid_id')->references('id')->on('grid');
$table->smallInteger('last_commandPos')->unsigned()->default(0);
$table->smallInteger('grid_pos_x')->unsigned();
$table->smallInteger('grid_pos_y')->unsigned();
$table->enum('rotation', App\Constants\RoverConstants::ORIENTATIONS);
$table->string('last_command');
Schema::enableForeignKeyConstraints();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('rover');
}
}
And I try to model the table rover with the following model:
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
use App\Model\Grid;
class Rover extends Model
{
/**
* Table Name
*/
protected $table='rover';
public function grid()
{
return $this->belongsTo(Grid::class);
}
public function setGridPosXValue($value)
{
}
public function setGridPosYValue($value)
{
}
}
And in a similar fashion the Grid model as well:
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
use App\Model\Rover;
class Grid extends Model
{
/**
* Table Name
*/
protected $table='grid';
public function rovers()
{
return $this->hasMany(Rover::class);
}
}
What I want to achieve is to access the width and height attributes from the Grid in order to check whether the grid_pos_x and grid_pos_y are smaller from the width and height using the methods setGridPosXValue and the setGridPosYValue respectively.
Do you know how to do that?

Looks like you have a one to many relationship setup here: https://laravel.com/docs/5.8/eloquent-relationships#one-to-many
To get the grid for a rover you can access it in multiple ways:
Directly:
$width = $Rover->grid->width;
$height = $Rover->grid->height;
With the builder methods:
$Grid = $Rover->grid()->first();
$width = $Grid->width;
$height = $Grid->height;

Related

Defining extended entities in sonata

I have some base entity that defines some fields which all (or at least most of) other entities should have. It looks like:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks()
*/
abstract class BaseEntity {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="boolean")
*/
protected $published;
/**
* #ORM\Column(type="datetime")
*/
protected $createdAt;
/**
* #ORM\Column(type="datetime")
*/
protected $updatedAt;
public function getId(): ?int
{
return $this->id;
}
and so on...getters and setters.
Then I have entity i.e. ArticleCategory extending that BaseEntity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ArticleCategoryRepository")
*/
class ArticleCategory extends BaseEntity
{
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
}
So, it's just adding one extra field - title.
Then, I have base admin class:
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use App\Entity\BaseEntity;
class BaseAdmin extends AbstractAdmin
{
/**
* #param BaseEntity $entity
*/
public function prePersist($entity)
{
$now = new \DateTime();
$entity->setCreatedAt($now);
$entity->setUpdatedAt($now);
$entity->setPublished(true);
}
}
And then admin class for that ArticleCategory entity:
namespace App\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
final class ArticleCategoryAdmin extends BaseAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('title', TextType::class);
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('title');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('title');
}
}
Problem is when I go to sonata list page instead of displaying all entities in ArticleCategory type I get an sql error:
Unknown column 'b0_.id' in 'field list'
And query looks like this:
SELECT b0_.id AS id_0, b0_.published AS published_1, b0_.created_at AS created_at_2, b0_.updated_at AS updated_at_3, a1_.title AS title_4
FROM article_category a1_
WHERE a1_.id IN (?, ?)
ORDER BY a1_.id ASC' with params [2, 3]
So sonata is getting data from correct table (article_category) and making an alias for it "a1_" and all fields that are directly inside ArticleCategory (title) are collected well, with that alias.
But all other fields that belong to base class (BaseEntity) sonata is trying to get via some un-existing alias "b0_" and query fails of course.
Any idea how to solve this? How to tell sonata that all the fields belong to the same table even they belong to 2 entity classes?
Found the problem. At the beginning where base entity was defined I had:
/**
* #ORM\Entity()
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks()
*/
Which is not correct because of that "Entity()" row. That had to be removed. It can't be entity and mapped supper class at the same time.
/**
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks()
*/

Laravel 5 - Blob doesn't retrive an image right

I'm using Laravel to store an image (generated from a canvas) but when I retrieve the value from the column and I pass it to the "src" attribute of an block it doesn't load and into the browser console I see the error
"Failed to load resource: net::ERR_INVALID_URL"
migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTblTaccuinoTable extends Migration
{
/**
* Schema table name to migrate
* #var string
*/
public $set_schema_table = 'tbl_taccuino';
/**
* Run the migrations.
* #table tbl_taccuino
*
* #return void
*/
public function up()
{
if (Schema::hasTable($this->set_schema_table)) return;
Schema::create($this->set_schema_table, function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id_taccuino');
$table->integer('id_paziente')->unsigned();
$table->string('taccuino_descrizione', 45);
$table->date('taccuino_data');
$table->binary('taccuino_report_anteriore');
$table->binary('taccuino_report_posteriore');
$table->index(["id_paziente"], 'fk_tbl_taccuino_tbl_pazienti1_idx');
$table->foreign('id_paziente', 'fk_tbl_taccuino_tbl_pazienti1_idx')
->references('id_paziente')->on('tbl_pazienti')
->onDelete('no action')
->onUpdate('no action');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists($this->set_schema_table);
}
}
Model
<?php
/**
* Created by Reliese Model.
* Date: Mon, 25 Dec 2017 12:47:05 +0000.
*/
namespace App\Models\Patient;
use Reliese\Database\Eloquent\Model as Eloquent;
/**
* Class Taccuino
*
* #property int $id_taccuino
* #property int $id_paziente
* #property string $taccuino_descrizione
* #property \Carbon\Carbon $taccuino_data
* #property boolean $taccuino_report_anteriore
* #property boolean $taccuino_report_posteriore
*
* #property \App\Models\Pazienti $tbl_pazienti
*
* #package App\Models
*/
class Taccuino extends Eloquent
{
protected $table = 'tbl_taccuino';
protected $primaryKey = 'id_taccuino';
public $incrementing = false;
public $timestamps = false;
protected $casts = [
'id_taccuino' => 'int',
'id_paziente' => 'int',
];
protected $dates = [
'taccuino_data'
];
protected $fillable = [
'id_paziente',
'taccuino_descrizione',
'taccuino_data',
'taccuino_report_anteriore',
'taccuino_report_posteriore'
];
public function tbl_pazienti()
{
return $this->belongsTo(\App\Models\Patient\Pazienti::class, 'id_paziente');
}
}
Inside my blade view
<img id="canvas_dolore" class="M" src="{{$record->taccuino_report_anteriore }}"></img>
PS: The blob string value starts with
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..."
You might try outputting unescaped src values for the image:
<img src="{!! ... !!}">

Symfony entity set array as single entity elements

i have problem, i would to add prototype array to database but this show me this error:
Expected argument of type "AppBundle\Entity\Tag", "array" given
...
Post ->setTag (array(array('value' => 'test'), array('value' => 'tess')))
here is my setter for tag:
public function setTag(\AppBundle\Entity\Tag $tag = null)
{
$this->tag = $tag;
return $this;
}
I Have two entities with relation, here relation:
class Post
{
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="post")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id")
*/
private $tag;
public function setTag(\AppBundle\Entity\Tag $tag = null)
{
$this->tag = $tag;
return $this;
}
}
and tag:
class Tag
{
/**
* #ORM\ManyToMany(targetEntity="Post", mappedBy="tag")
*/
private $post;
}
Source:
http://snipet.co.uk/kR
http://snipet.co.uk/gcf
http://snipet.co.uk/0VI
You're trying to model a bidirectional many-to-many relation between Post and Tag.
So, first of all, your getters need to return a collection of objects, and your setters need to accept a collection of objects - not only one single object as in your code (your setTag method accepts a parameter of type Tag - but you need an array-like parameter).
Secondly, the Doctrine framework does not work with simple PHP arrays, but with implementations of \Doctrine\Common\Collections\Collection.
Next, you need to initialize your collection fields in the constructors of your entity classes with an implementation of the Collection class - you can use \Doctrine\Common\Collections\ArrayCollection.
So your entity classes should look rather like this:
/**
* #ORM\Entity
*/
class Post
{
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="posts")
* #ORM\JoinTable(name="posts_tags")
*/
private $tags;
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getTags()
{
return $this->tags;
}
public function setTags(\Doctrine\Common\Collections\Collection $tags)
{
$this->tags = $tags;
}
}
/**
* #ORM\Entity
*/
class Tag
{
/**
* #ORM\ManyToMany(targetEntity="Post", mappedBy="tags")
*/
private $posts;
public function __construct()
{
$this->posts = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getPosts()
{
return $this->posts;
}
public function setPosts(\Doctrine\Common\Collections\Collection $posts)
{
$this->posts = $posts;
}
}
I strongly advise you to read once again the documentation of the Doctrine framework, how to annotate your entities, and how to model relations: http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html

How can I create a dual has_many relationship in Laravel?

I have a database with a Employee table and a Customer table. The Employee table has 2 one_to_many relationships with the Customer table; the foreign keys in the Customer table are 'primary_sales_contact_id' and 'primary_service_contact_id'. Both obviously refer to the id field on the Employee table.
How do I set up a migration for this, and how would I subsequently create a model for it? I'm a newbie in Laravel, so apologies if its blindingly obvious, and thanks for your time.
Employee migration
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateEmpoyeeTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('employee', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('employee');
}
}
Customer migration
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCustomerTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('customer', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->integer('primary_sales_contact_id')->unsigned();
$table->integer('primary_service_contact_id')->unsigned();
$table->foreign('primary_sales_contact_id')->references('id')->on('employee');
$table->foreign('primary_service_contact_id')->references('id')->on('employee');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('customer');
}
}
Employee model
class Employee extends Eloquent
{
protected $table = 'employee';
public $timestamps = false;
public function customersService() {
return $this->hasMany('Customer', 'primary_service_contact_id');
}
public function customersSale() {
return $this->hasMany('Customer', 'primary_sales_contact_id');
}
}
Customer model
class Customer extends Eloquent
{
protected $table = 'customer';
public $timestamps = false;
public function primarySalesContact() {
return $this->belongsTo('Employee', 'primary_sales_contact_id');
}
public function primaryServiceContact() {
return $this->belongsTo('Employee', 'primary_service_contact_id');
}
}
All stuff use like:
$customer = Customer::find(1);
echo $customer->primaryServiceContact;
$employee = Employee::find(1);
echo $employee->customersSale;

ORM Self-referenced entity not persisting into database properly

ive been trying to figure this out for 2 hours now and i cant seem to understand what went wrong.
I am using Symfony2 and FOSUserBundle.
I created a User entity which extends FOSUserBundle's BaseUser class. Within this User entity, i have 3 variables, id, my_mentors and my_mentees. More details are below:
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="my_mentees")
*/
protected $my_mentors;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="my_mentors")
* #ORM\JoinTable(name="mentor_and_mentee_relationship",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="mentors_or_mentees_user_id", referencedColumnName="id")}
* )
*/
protected $my_mentees;
public function __construct()
{
parent::__construct();
$this->my_mentors = new ArrayCollection();
$this->my_mentees = new ArrayCollection();
}
public function __toString()
{
return $this->getUsername();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add my_mentors
*
* #param Fitness\FitBundle\Entity\User $myMentors
*/
public function addUser(\Fitness\FitBundle\Entity\User $myMentors)
{
$this->my_mentors[] = $myMentors;
}
/**
* Get my_mentors
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMyMentors()
{
return $this->my_mentors;
}
/**
* Get my_mentees
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMyMentees()
{
return $this->my_mentees;
}
}
I created the self reference because a Mentee(which is a User) will subscribe to a Mentor(which is also a User). I tried to do this using the following function:
public function subscribeAction($menteeID, $mentorID)
{
$em = $this->getDoctrine()
->getEntityManager();
$mentor = $em->getRepository('TestBundle:User')
->find($mentorID);
$mentee = $em->getRepository('TestBundle:User')
->find($menteeID);
$currentMentors = $mentee->getMyMentors();
if ($currentMentors->contains($mentor))
$this->get('session')->setFlash('subscribe-notice', 'You have already signed up to this mentor!');
else
{
$mentee->setIsMentor(false);
$mentee->addUser($mentor);
$mentor->addUser($mentee);
$em->persist($mentee);
$em->persist($mentor);
$em->flush();
$this->get('session')->setFlash('subscribe-notice', 'Subscription succesful!');
}
return $this->redirect($this->generateUrl('TestBundle_testpage', array('id' => $mentor->getMentorProfile()->getId()) ));
}
The problem here is that when i check the database, it does not persist the data. The mentor-mentee relationship information is not stored in the table "mentor_and_mentee_relationship" as declared by the annotation.
I persisted both $mentor and $mentee in an attempt to get it to work, but apparently it doesnt.
Could my ORM annotation be declared wrongly?
You are using the same function (addUser) to add a mentor and to add a mentee. This is wrong. First you need two different setters in your entity (I changed the name of addUser to make it clear)
/**
* Add my_mentors
*
* #param Fitness\FitBundle\Entity\User $myMentors
*/
public function addMentor(\Fitness\FitBundle\Entity\User $myMentors)
{
$this->my_mentors[] = $myMentors;
}
/**
* Add my_mentees
*
* #param Fitness\FitBundle\Entity\User $myMentees
*/
public function addMentee(\Fitness\FitBundle\Entity\User $myMentees)
{
$this->my_mentees[] = $myMentees;
}
Then in your controller do:
$mentee->addMentor($mentor);
$mentor->addMentee($mentee);

Resources