I've come up against a strange issue which I cannot seem to figure out.
I'm creating a CRM in Symfony 2 implementing Doctrine, and using an OpenCart database.
There is the ability to add an order via the CRM which persists the data given into the relevant tables, but I'm falling at the final hurdle. I'm trying to persist the order ID yet for some reason I'm getting the error:
order_id cannot be null
This is how the entity entry is set up in the file:
/**
* #var integer
*
* #ORM\Column(name="order_id", type="integer", nullable=false)
*/
private $orderId;
And I'm using this to set it:
$order_option->setOrderId($order_id);
I know for a fact that $order_id has an integer value, as I've printed it out before persisting (I even tried hard coding it into the set function) but it still ends up being null.
I am confused as to why this is happening since every other set is working, plus it's even correctly assigned the value to the $this->orderId variable as I tried debugging that too.
If anyone can maybe shed some light on this I would be grateful.
You have probably forgotten to add #ORM\Id
/**
* #var integer
*
* #ORM\Column(name="order_id", type="integer", nullable=false)
* #ORM\Id
*/
private $orderId;
Figured it out!
There was a protected variable called $product in the entity which was being joined by order_id, however this is never persisted or referenced. So, I just deleted it and now the order_id is persisted as normal.
Related
I know the title is not really explaining the problem so I will try to give more details.
I have a String in the Controller, something like this (keep in mind that this String is not manually written since it's dynamic, there are 7 filters and I want to return the information based on the filters selected, so I can't just put the String in the #Query value, since some filters will remain untouched and you cannot SELECT * WHERE value = *)
String query = "SELECT * FROM table WHERE column1=value1 AND column2=value2"
Now, the Queries are made in the Repository, but I really have no idea how to make the value of that query to be this String, something like this :
#Query(value = query, nativeQuery = true)
public List<ExampleEntity> testFunction(String query);
My first idea was to do this :
#Query(value = "?", nativeQuery = true)
public List<ExampleEntity> testFunction(String query);
But it inputs the whole String inside ' '
'SELECT * FROM table WHERE column1=value1 AND column2=value2'
(now that I think about this, it does that because the compiler sees this as like I'm trying to set the value of something to be the String, makes sense but I wish there could be a way to simply set the input of the function to be the value of the Query :/ )
Sooo ... is there any other way to use that string as the query value?
Annotations are on classes, they are set at compile time. You can’t change them at runtime. Spring can’t change them either.
What you could do is check out how to use Specifications to construct queries, or use your existing query constructing code within a custom JPA repository. Defining repositories with interfaces is a good option for simple cases, but this is not a simple case.
It would be better to move your query building code out of the controller layer and into the repository, btw. Even assuming everything in the current workflow is secure, having a repository take a native query as a parameter just isn’t a good look, it’s wide open to abuse.
I took a different approach to solve this problem that is much simpler than using Specifications.
After searching how can you send a Query in the Controller I found jdbcTemplate that is Standard in Spring (no need to add a dependency or anything else)
These are the steps that I took and in the end, everything works at it should.
1 Autowire the JdbcTemplate in the Controller
#Autowired
private JdbcTemplate jdbcTemplate;
2 Set the return to be the Query
return jdbcTemplate.queryForList(query);
Keep in mind that this is for multiple Columns, if you have to return only one column I think you have to use something like this :
return jdbcTemplate.query(query, new SingleColumnMapper(Example.class)
It might not be the safest or the most recommended way of solving this, but it worked for me.
My models have both id and counter attributes. The id is a UUID, and the counter is an integer which is auto-incremented by the database.
Both are unique however I rely on id as the primary key. The counter is just a human-friendly name that I sometimes display to the user.
Immediately before an object is created a listener gives it a UUID. This works fine.
When the record is saved, MySQL increments the counter field. This works fine except that the copy of the object which I have in memory does not have the counter value. I can reload the object to find out what its counter is, but that would require another database query.
Is there a way to find the value of the counter without a specific database query? For example, is it returned as part of the response from the database when a record is created?
Few things:
Use create(array $attributes) and you'll get exactly what you want. For this having right, you have to ensure that $fillable array consists all attributes' names passed to create method.
You should use Observer on model instead of listener (most likely creating method).
Personal preference using Eloquent is that you should use id for id (increment field) and forget custom settings between models because by default it is what relations expect and so on
public function secondModels()
{
return $this->hasMany(SecondModel::class);
}
is pretty much no brainer. But for having this working best way would be (also following recommendations of this guy) FirstModel::id, SecondModel::id, SecondModel::first_model_id; first_models, second_models as table names. Avoiding and/or skipping this kind of unification is lot of custom job afterward. I don't say it can't be done but it is lot of non-first-time-successful work done.
Also, if you want visitor to get something other than id field name, you can make computed field with accessor:
/**
* Get the user's counter.
*
* #return string
*/
public function getCounterAttribute(): string
{
return (string)$this->id;
}
Which you call then with $user->counter.
Also personal preference of mine is to have most possible descriptive variable names so uuid field of mine would be something like
$table->uuid('uuid4');
This is some good and easy to make practice of Eloquent use.
Saying all this let me just to say that create() and save() will return created object from database while insert() shall not do it.
I'm using PhpStorm. When I put the following PHPDoc documentation for a function:
/**
* #param $id application identifier
*/
public function foo($id)
And I run the "Quick documentation" (Ctrl + Q) command for the function in PHPStorm, it shows this:
Parameters: App\Models\Application $id identifier
It looks like for some reason, the IDE is interpreting the first word of the parameter description, application, as the type for the parameter. I don't want to specify the type of the parameter (I don't know what it is), I just want to add a brief description about the parameter in the documentation. What should I do?
If you don't know what it is, you can use mixed. The type goes before the $id and the part after $id will be used as the description.
/**
* #param mixed $id application identifier
*/
public function foo($id)
I have 2 entities: User and Archive, with a many to many relation between them:
In user entity I have:
/**
* represent the script collection for a user
* #ORM\ManyToMany(targetEntity="My\ApplicationBundle\Entity\Archive", inversedBy="users")
* #ORM\JoinTable(name="collection")
**/
private $collection;
and in Archive:
/**
* represent the users having this archive in their collection
* #ORM\ManyToMany(targetEntity="My\UserBundle\Entity\User", mappedBy="collection")
**/
private $users;
this relationship generates a table called "collection" with an user_id and an archive_id field. Insert data in these table is not a problem.
now, I'd like to get all the archive for a specific user, but I don't know where to start. I tried
$this->getUser->getCollection()
but it seems not working as expected. Probably I'd need some custom repository class? Many thanks
Circumstances
I have three models/db-tables related with 1:n each: An order has multiple commissions and a commission has multiple commission_positions. Therefore the commission_position has an FK-field containing a commission id. The commission itself has an FK-field containing the id of an order.
Order > Commission > CommissionPositions
Problem
What I need to do now is select all the CommissionPositions having a certain value in the related Order-Model. Obvious solution is to use the Query-Object of CommissionPosition which I extended with a named scope. The named scope looks like this:
class CommissionPositionQuery extends ActiveQuery
{
/**
* Named scope to filter positions of a certain alpha order id
* #param integer $id the alpha order id
* #return \common\models\query\CommissionPositionQuery
*/
public function alphaOrderId($id)
{
//TODO: with not working
$this->with(['commission.order']);
$this->andWhere(['alpha_order_id'=>$id]);
return $this;
}
}
The relation commission is defined on the Commission-Model and working. The second relation order is defined on the commission-model and working as well. The filtered field alpha_order_id is in the Order-Table. Now I execute the query like this:
$filteredPositions = CommissionPosition::find()->alphaOrderId(17)->all();
The scope is called successfully and the where-part is used, but when I check the generated SQL I see no join-statements even though I use the with-method to tell yii to fetch the relation together. The response is 'unknown column alpha_order_id' which makes sense as there is no join to the related tables. This is the generated SQL:
SELECT * FROM `commission_position` WHERE (`alpha_order_id`=17)
What am I missing? Is this a bug of Yii2?
Found the soution myself. The naming changes between Yii1 and Yii2 lead to a little confusion. To prevent others from wasting time here the details:
Yii1
In yii 1 you would join in a relation (exemplary: commission) directly like this:
$query->with = 'commission'
$query->together = true;
Yii2 / difference
When calling the with-method like showed in the question the relation was successfully added to the with-array of the ActiveQuery. However, when executing the query, the join part was missing.
Solution
Seems like the with-method is NOT the way to go. Instead I used the method called joinWith with the following signature:
public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN')
Now as described in the answer I defined the relation as the first argument ('commission.order') and left the rest as is, because the default values are perfectly fine. Pay attention to the default value of the second parameter. this makes sure the relations are joined in directly!
Voilà...the resulting sql contains the needed joins. One pitfall is to be considered though: Ambigious column namings is of course to be handled by ourselves! Link to the documentation of the method:
http://www.yiiframework.com/doc-2.0/yii-db-activequery.html#joinWith()-detail
If you want a JOIN use:
$this->joinWith(['commission.order']);