Table hasOne relation not being created - laravel-5.3

I have a tables table with the model defined like so:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Table extends Model
{
public function location()
{
return $this->hasOne('App\Location');
}
}
And I have a locations table with a table_id column, and the model defined like so:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
public function table()
{
return $this->belongsTo('App\Table');
}
}
I have seeded the database with a sample location, which has an id of 1. Inside my controller, inside a DB::transaction block, I run the following code:
$table = new Table;
$location = Location::findOrFail(1);
$table->location()->save($location);
$table->saveOrFail();
This code runs without error, however, when I look at the database, the table_id column for my location is still empty. What am I doing wrong?
I have also tried the following, to no avail:
$table = new Table;
$location = Location::findOrFail(1);
$table->saveOrFail();
$location->table()->associate($table);
Only the following seems to work:
$table = new Table;
$table->save();
$location = Location::findOrFail(1);
$location->table_id = $table->id;
$location->save();

You are doing it the opposite way. Try the following:
$table = new Table;
$location = Location::findOrFail(1);
$location->table()->associate($table);
$location->save();
What you really need to do is associate the foreign key of the instance to a new object, and the foreign key is in the Location model.

Related

Tornadofx Javafx - How to reload a view / component

So its a basic question.
What I am trying to achieve is refreshing views from another views.
Lets say I have a view EmployeeTableView which shows a tabular representation of employees by doing a REST API call.
In another view, I have a the filter EmployeeFilterView wherein I have gender, salary range, employee type, etc.
I also have a userContext object in which I store the user preferences. So by default lets say I have stored the value of gender filter to be Male, salary range to be ALL, etc. This object is send as a parameter to the EmployeeTableView.
When the EmployeeTableView is loaded I do a restAPI call with the userContext values to get the employee details. So that works fine. Now I change the gender filter to Female and assign this value in my userContext.
Now if I could just reload the EmployeeTableView with the userContext object, the restapi call would get the updated values.
But how can I do that ?
Also suggest a better approach if you have.
The EventBus is one valid solution to this. Another would be to use a ViewModel or Controller as the UserContext object and let that include the actual observable list of employees and then bind that list to the TableView in EmployeeTableView. Whenever the list in the context is updated, the TableView will update as well.
The filter view would call a function in the UserContext to perform the actual REST call and update the list of employees based on that.
You could create a separate EmployeeQuery object that can be injected into both the EmployeeFilterView and the UserContext so it can extract the selected filter values to perform the query. This query object contains a list of all the search parameters you want to pass to the server.
You could also consider creating a separate scope to keep these components separated if that makes sense to your architecture.
Exactly how you define these components are mostly a matter of taste, here is one suggestion. I used the RangeSlider from ControlsFX for the mock search UI.
To make it easier to imagine how this ties together, here is a screenshot:
(All names and salaries are fiction :)
/**
* The employee domain model, implementing JsonModel so it can be fetched
* via the REST API
*/
class Employee : JsonModel {
val nameProperty = SimpleStringProperty()
var name by nameProperty
val salaryProperty = SimpleIntegerProperty()
var salary by salaryProperty
val genderProperty = SimpleObjectProperty<Gender>()
var gender by genderProperty
override fun updateModel(json: JsonObject) {
with (json) {
name = getString("name")
salary = getInt("salary")
gender = Gender.valueOf(getString("gender"))
}
}
}
enum class Gender { Male, Female }
/**
* Container for the list of employees as well as a search function called by the filter
* view whenever it should update the employee list.
*/
class EmployeeContext : Controller() {
val api: Rest by inject()
val query: EmployeeQuery by inject()
val employees = SimpleListProperty<Employee>()
fun search() {
runAsync {
FXCollections.observableArrayList(Employee().apply {
name = "Edvin Syse"
gender = Gender.Male
salary = 200_000
})
//api.post("employees/query", query).list().toModel<Employee>()
} ui {
employees.value = it
}
}
}
/**
* Query object used to define the query sent to the server
*/
class EmployeeQuery : ViewModel(), JsonModel {
val genderProperty = SimpleObjectProperty<Gender>(Gender.Female)
var gender by genderProperty
val salaryMinProperty = SimpleIntegerProperty(50_000)
var salaryMin by salaryMinProperty
val salaryMaxProperty = SimpleIntegerProperty(250_000)
var salaryMax by salaryMaxProperty
val salaryDescription = stringBinding(salaryMinProperty, salaryMaxProperty) {
"$$salaryMin - $$salaryMax"
}
override fun toJSON(json: JsonBuilder) {
with(json) {
add("gender", gender.toString())
add("salaryMin", salaryMin)
add("salaryMax", salaryMax)
}
}
}
/**
* The search/filter UI
*/
class EmployeeFilterView : View() {
val query: EmployeeQuery by inject()
val context: EmployeeContext by inject()
override val root = form {
fieldset("Employee Filter") {
field("Gender") {
combobox(query.genderProperty, Gender.values().toList())
}
field("Salary Range") {
vbox {
alignment = Pos.CENTER
add(RangeSlider().apply {
max = 500_000.0
lowValueProperty().bindBidirectional(query.salaryMinProperty)
highValueProperty().bindBidirectional(query.salaryMaxProperty)
})
label(query.salaryDescription)
}
}
button("Search").action {
context.search()
}
}
}
}
/**
* The UI that shows the search results
*/
class EmployeeTableView : View() {
val context: EmployeeContext by inject()
override val root = borderpane {
center {
tableview(context.employees) {
column("Name", Employee::nameProperty)
column("Gender", Employee::genderProperty)
column("Salary", Employee::salaryProperty)
}
}
}
}
/**
* A sample view that ties the filter UI and result UI together
*/
class MainView : View("Employee App") {
override val root = hbox {
add(EmployeeFilterView::class)
add(EmployeeTableView::class)
}
}
I ended up using Tornadofx -> EventBus
Basically, when I change any of the filters, I fire an even which rebuilds the Node with the updated values.
Not sure whether the approach is right, that's why still keeping it open for discussion.

HasOne relationship returns null on save

I have two models A and B with a foreign key on A of b_id on the id of B. the model code is as follows
A has a trait BB with the following methods
public function b() // shared by multiple models
{
return $this->hasOne(B::class, 'id', 'b_id'); // table has foreign keys setup
}
public function saveB($params){
$b = $this->b;
if(is_null($b)) $b = new B;
else $b->a()->dissociate($b->id); // if there is a b break the link between them
if($b->setParams($params) === true)
{
try {
$this->b()->save($b);
$this->save();
} catch (Exceptio ....... throw an exception if anything
}
B is a model with the method
public method setParams($params) {
$this->trigger = $params[0];
$this->colour = $params[1];
.... arbitrary stuff not related;
}
The problem arises out of the following TestCase logic
public function setUp()
{
parent::setUp();
$this->a = A::find(237); // actual record
$this->a->saveB(['trigger'=>1,'colour'=>'orange']);
}
public function testSaveB(){
$this->assertGreaterThan(0, $this->a->b_id);
}
The assertGreaterThan test fails and the b_id is null even though the following is true
The table foreign keys exists
Appropriate fields are fillable
The data for B is inserted( no previous record existed)
The record exists and b_id was NULL from inception
No exceptions are thrown
Note the model names have been changed to make things easier to understand but the functions are more or less exactly as I have it
Does this logic model->hasOne()->save(model) inserts the newly created model and updates the foreign key for it? or do i have to still update the key/ value and $a->update() rather than $a->save()?

Laravel Eloquent hasMany returns null

Laravel 4 is giving me unexpected results on a new project. To try and help me better understand the results I tried what I thought would be a simple exercise and use a friends old WordPress blog on his web hosting.
Post model:
class Post extends Eloquent {
protected $table = 'wp_posts';
public function meta()
{
return $this->hasMany('Meta', 'post_id');
}
}
Meta model
class Meta extends Eloquent {
protected $table = 'wp_postmeta';
public function post()
{
return $this->belongsTo('Post');
}
}
I have tried all of these variations with no avail...
TestController:
public function get_index()
{
// $test = Post::with('Meta')->get();
// $test = Post::with('Meta')->where('id', '=', '219')->first();
// $test = Post::find(219)->Meta()->where('post_id', '=', '219')->first();
// $test = Post::find($id)->Meta()->get();
// $test = Meta::with('Post')->get();
$id = 219;
$test = Post::find($id)->meta;
return $test;
}
returned in the event listener:
string(47) "select * from `wp_posts` where `id` = ? limit 1" string(65) "select * from `wp_postmeta` where `wp_postmeta`.`post_id` is null" []
Please tell me I am just overlooking something really minor and stupid and I just need some sleep.
Though is that while the SQL is case-insensitive, the array of attributes the model gets populated with is a PHP array where indexes are case-sensitive. The schema had the primary key as ID

Symfony2 rejecting my custom findBy function in my model class

I followed the example of setting up a custom findOneByJoinedToCategory($id) function in the Doctrine model class as explained in the documentation here:
http://symfony.com/doc/current/book/doctrine.html
In my case, I have a model class called TestVendorCategory containing a bunch of attributes and this function:
public function findOneByNameJoinedToVendorCategoryMappings($vendorCategoryName)
{
$query = $this->getEntityManager()
->createQuery('
SELECT vc, vcm FROM TestCoreBundle:VendorCategory vc
JOIN vcm.vendorCategoryMapping vcm
WHERE vc.name = :name'
)->setParameter('name', $vendorCategoryName);
try
{
return $query->getSingleResult();
}
catch (\Doctrine\ORM\NoResultException $e)
{
return null;
}
}
In my controller, I call it like this:
$vendorCategoryMapping = $this->em->getRepository("TestCoreBundle:VendorCategory")->findOneByNameJoinedToVendorCategoryMappings($vendorCategoryName);
When I go to the browser and execute this action with this call in it, I get the following error message:
Entity 'Test\CoreBundle\Entity\VendorCategory' has no field 'nameJoinedToVendorCategoryMappings'. You can therefore not call 'findOneByNameJoinedToVendorCategoryMappings' on the entities' repository
It looks like Symfony 2.1 wants the findOneBy...() methods to reflect names of existing fields only, no custom "JoinedTo..." kinds of methods. Am I missing something, please? The documentation shows an example like this where it supposedly works. I am using annotations, but this method doesn't have any. Thank you!
You have to put the findOneByNameJoinedToVendorCategoryMappings function in the VendorCategoryRepository class:
<?php
namespace Test\CoreBundle\Entity;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
class VendorCategoryRepository extends EntityRepository
{
public function findOneByNameJoinedToVendorCategoryMappings($vendorCategoryName)
{
$query = $this->getEntityManager()
->createQuery('
SELECT vc, vcm FROM TestCoreBundle:VendorCategory vc
JOIN vcm.vendorCategoryMapping vcm
WHERE vc.name = :name'
)->setParameter('name', $vendorCategoryName);
try
{
return $query->getSingleResult();
}
catch (NoResultException $e)
{
return null;
}
}
}
and link this repository class in the Entity:
/**
* #ORM\Entity(repositoryClass="Test\CoreBundle\Entity\VendorCategoryRepository")
*/
class VendorCategory

Flex combo box labelfunction

I have two questions regarding the Flex combo box.
The string representing the function name will be read from xml # run time.
var combo:ComboBox = new ComboBox();
combo.labelFunction = "functionName";
How can I achieve this?
So the first name, which is to be displayed in the combo box, can be only retrieved by accessing another DTO, called person and then its first name.
var combo:ComboBox = new ComboBox();
combo.labelField= "person.firstName";
My class looks like this,
public class Test
{
public var person:PersonDTO;
}
public class PersonDTO
{
public var firstName:String;
}
Is it possible to access any multi-level text using the combo box label field ?
You need to pass the function not the name.
Doing this
combo.labelFunction = "functionName";
Is passing a string.
The only work around I can think of is to make a switch statement with one case for each function you may have. Then call that with "case" from within your xml.
switch( xml.#labelfunction ){
case 'func1':
combo.labelFunction = this.func1;
break;
case 'func2':
combo.labelFunction = this.func2;
break;
}
Its hacky but should work.
ad 1) labelFunction
Calling functions when you know only the name as String is quite easy. The following snippets shows how you can execute a function that is a member of the same class. In case you need to call a function from another class replace this with the according variable name.
private function comboBox_labelFunction(item:Object):String
{
var functionName:String = myXml.#labelFunctionName;
return this[functionName](item);
}
ad 2) labelField
It's normally not possible to use "person.firstName" as labelField. However, you should be able use it within your labelFunction. Something like this should work...
private function comboBox_labelFunction(item:Object):String
{
var labelField:String = "person.firstName";
var attributeNames:Array = labelField.split(".");
for each (var attributeName:String in attributeNames)
{
if (item && item.hasOwnProperty(attributeName))
item = item[attributeName];
else
return null;
}
return item;
}

Resources