How can I check if an order with a given increment id already exists in magento? - magento

I am new to Magento.
What's the proper way to check if an order with a given increment id already exists ?
The obvious way:
$order = Mage::getModel('sales/order')->loadByIncrementId($reservedOrderId);
if ($order) {
Mage::log('already have order with id ' . $reservedOrderId);
return $order;
}
does not work, because I get a new and empty model instance back.
What's the correct way in magento to see if I have no such model for that id ?

The most common approach I've seen in core code just load()s a model and checks if there was a primary key assigned. In your case this would look like the following - note the very slight adjustment to the logical condition ($object->getId() vs. $object):
$order = Mage::getModel('sales/order')->loadByIncrementId($reservedOrderId);
if ($order->getId()) {
Mage::log('already have order with id ' . $reservedOrderId);
return $order;
}
It's a simple mistake, but remember that a call to load data on a Magento data model will always return the object instance. It's only if there is a result from the storage backend that the object would be decorated with data and therefore a primary key.

In my experience there are two ways to do this:
if ($order->hasData()) {
// order already exists
}
or, by using a collection;
$collection = Mage::getModel('sales/order')->getCollection()->addFieldToFilter('increment_id', $reservedOrderId);
if ($collection->count()) {
// order already exists
}
In your case, probably best to use the first one.

There's multiple ways to approach this. First, since you know the increment ID to expect, you could check for it after you get your model back
$increment_id = '100000002';
$order = Mage::getModel('sales/order')->loadByIncrementId($increment_id);
if($order->getIncrementId() == $increment_id)
{
var_dump("Increment IDs match, that means there's an order");
}
else
{
var_dump("Increment IDs don't match, that means there's no order");
}
Similarly, although there's a model returned even if there's no match, you could check that model's data — an empty array means nothing was loaded
$increment_id = '100000002';
$order = Mage::getModel('sales/order')->loadByIncrementId($increment_id);
if($order->getData())
{
var_dump("Data array means there's an order");
}
else
{
var_dump("Empty data array means there's no order");
}
Finally, you can load a collection with an increment id filter, and check how many items it contains
$increment_id = '100000002';
$c = Mage::getModel('sales/order')->getCollection()
->addFieldToFilter('increment_id',$increment_id);
if(count($c) > 0)
{
var_dump("A collection with more than zero items means the order exists");
}
else
{
var_dump("An empty collection means it does not");
}
I prefer the last approach for a simple "does/does-not" exists check, as a collection doesn't trigger a model's after load method which means it's theoretically more performant. That said, no approach is more valid than the other — just try to use the same technique everywhere for more readable code.

Related

Best Practice - Laravel Controller Eloquent merge

I have a scope on my Supplier model that returns results where active = true.
This works great when creating new entries, as I only want the user to see active suppliers.
Current entries may have an inactive supplier; When I edit it, I want to see all active Suppliers, plus the current supplier (if it is inactive)
I have this code in my controller:
$suppliers = Supplier::active()->get();
if (!$suppliers->contains('id', $record->supplier->id))
{
$suppliers->add(Supplier::find($record->supplier->id));
}
Two questions: Is this the correct way to do this? Should this code be in my controller or should I have it somewhere else? (perhaps a scope but I wouldn't know how to code that).
Edit:
Thanks for the help guys. I have applied advice from each of the answers and refactored my code into a new scope:
public function scopeActiveIncluding($query, Model $model = null)
{
$query->where('active', 1);
if ($model && !$model->supplier->active)
{
$query->orWhere('id', $model->supplier->id);
}
}
What you've written will work, but the Collection::contains function can potentially be pretty slow if the collection is large.
Since you have the id, I would probably make the following change:
$suppliers = Supplier::active()->get();
$supplier = Supplier::find($record->supplier->id);
if (!$supplier->active) {
$suppliers->add($supplier);
}
Of course, the downside to this is that you may be making an unnecessary query on the database.
So you have to consider:
is the record's supplier more likely to be active or inactive?
is the size of the collection of active suppliers large enough to justify another (potentially wasted) call to the database?
Make the choice that makes the most sense, based on what you know of your application's data.
As for the second question, if you will only need this specific set of suppliers in this one part of your application, then the controller is a good place for this code.
If, however, you will need this particular set of suppliers in other parts of your application, you should probably move this code elsewhere. In that case, it might make sense to create a function on the the related model (whatever type $record is...) that returns that model's suppliers set. Something like:
public function getSuppliers()
{
$suppliers = Supplier::active()->get();
$supplier = $this->supplier;
if (!$supplier->active) {
$suppliers->add($supplier);
}
return $suppliers;
}
I saw #Vince's answer about 1st question, and I'm agree with him.
About 2nd question:
Write scope in Supplier model like this:
public function scopeActive($query){
$query->where('active', 1); // for boolean type
}
For good practice, you need to write the logic parts in services like "App\Services\SupplierService.php". And there write the function you want:
public function activeSuppliersWithCurrent($record) {
$suppliers = Supplier::active()->get();
$supplier = Supplier::find($record->supplier->id);
if (!$supplier->active) {
$suppliers->add($supplier);
}
}
In your SupplierController's constructor inject the instance of that service and use the function, for example:
use App\Servives\SupplierService;
protected $supplierService = null;
public function __construct(SupplierService $supplierService) {
$this->supplierService = $supplierService;
}
public function getActiveSuppliersWithCurrent(...) {
$result = $this->supplierService->activeSuppliersWithCurrent($record);
}
As you can see, later you will not need to change anything in controller. If you'll need to change for example the query of suppliers selection, you will just have to change something only in service. This way will make your code blocks separated and shorter.
Also the sense for this pattern: you don't need to access the models from controller. All logic related with models will implemented in services.
For other projects you can grab only services or only controllers, and implement another part differently. But in that case if you had all codes in controller, that will prevent you to grab the portions of necessary codes, cuz may you don't remember what doing each blocks...
You could add a where clause to the query to also find that id.
$suppliers = Supplier::active()->orWhere('id', $record->supplier->id)->get();
You could potentially slide this into the active scope by passing the 'id' as an argument.
public function scopeActive($query, $id = null)
{
$query->where('active', true);
if ($id) {
$query->orWhere('id', $id);
}
}
Supplier::active($record->supplier->id)->get();
Or make another scope that does this.

Check if session variable is defined

I need to count the number of views. I am using a session variable to avoid duplicate count. I need to check if session view_count isset and then it is set to false and increment the view count
$currentPost = Post::where('slug',$slug)->first();
$comments = \App\Comment::where('post_id',$currentPost->id)->get();
if(\Session::get('view_count')) {
\Session::put('view_count', false);
$currentPost->view_count = $currentPost->view_count + 1;
$currentPost->save();
}
Can't you just do
if (Session::has('your_key'))
{
//your code here
}
Update answer
Determining If An Item Exists In The Session
To determine if an item is present in the session, you may use the has method. The has method returns true if the item is present and is not null:
if ($request->session()->has('users')) {
//
}
To determine if an item is present in the session, even if its value is null, you may use the exists method. The exists method returns true if the item is present:
if ($request->session()->exists('users')) {
//
}
I am assuming you want to check whether a visitor has viewed a certain blog post, in which case, I'd probably do something like this.
$currentPost = Post::where('slug', $slug)->first();
// You should also probably set up your relationship with Comments
$comments = \App\Comment::where('post_id', $currentPost->id)->get();
if(! in_array($currentPost->id, session()->get('posts_viewed', []))) {
session()->push('posts_viewed', $currentPost->id);
// Your increment could also be simplified as follows
$currentPost->increment('view_count');
}
In your particular case, you will only be able to track whether the user has viewed one particular blog post. However, if you use an array and keep pushing viewed blog posts into it, you would be able to track views across many blog posts.

Retrieving records from database using eloquent with optional query parameters

i have the following block of code in my Resource Controller:
$travel_company_id = Input::get('travel_company_id');
$transport_type = Input::get('transport_type');
$route_type = Input::get('route_type');
$travelRoutes = TravelRoute::where('travel_company_id', $travel_company_id)
->where('transport_type', $transport_type)
->where('route_type', $route_type)
->get();
Now what this does is it gets travelRoutes based on the parameters supplied. What i want is for it to do is perform a search based on the available parameters, that way if $route_type is empty the search will be performed only on travel_company_id and transport type.
Also if all the parameters are empty then it will simply do a get and return all available records.
I know i can do this with lots of if statements but then if i add a new parameter on the frontend i will have to add it to the backend as well, I was wondering if there was a much simpler and shorter way to do this in laravel.
The where method accepts an array of constraints:
$constraints = array_only(Input::all(), [
'travel_company_id',
'transport_type',
'route_type',
]);
$routes = TravelRoute::where($constraints)->get();
Warning: do not use Input::only() instead of array_only(). They're not the same.
Input::only() fills in any missing items with null, which is not what you want here.
This is pretty hacky and if you spend some time developing a solution I'm sure it could be much nicer. This assumes all the fields in the getSearchFields() function match the input names from the form and database.
/**
* Search fields to retrieve and search the database with. Assumed they match the
* column names in the database
*/
private function getSearchFields()
{
return ['travel_company_id', 'transport_type', 'route_type'];
}
public function search()
{
// Get a new query instance from the model
$query = TravelRoute::query();
// Loop through the fields checking if they've been input, if they have add
// them to the query.
foreach($this->getSearchFields() as $field)
{
if (Input::has($field))
{
$query->where($field, Input::get($field));
}
}
// Finally execute the query
$travelRoutes = $query->get();
}

Laravel Has One Relation changing the identifier value

I'm not sure this is a real relation. I will try to explain the best way I can.
So first of all, I have three models :
Appartement,
AppartementPrice
The AppartementPrice depends on :
- appartement_id
I would like the AppartementPrice to be retrieve like that :
If there is a specific price for the appartement, then retrieve it, If not retrieve the price for all appartement which is stored in the database with an appartement_id = 0.
So basically what I would like is to do something like that :
public function price()
{
if(isset($this->hasOne('AppartementPrice')->price) // Check that relation exists
return $this->hasOne('AppartementPrice');
else
return $this->hasOne('AppartementPrice')->where('appartement_id', '0');
}
But this is not working.
It does not retrive me the default price.
I guess anyway this is not a best practice ?
I first tried to get the informations like that :
//Check if appartment has a specific price or retrieve default
if($priceAppartement = AppartementPrice::getPriceByCompanyAppartement($this->id))
return $priceAppartement;
else
return AppartementPrice::getDefaultPrice();
But I had this error :
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
when doing :
echo $app->price->price;
How can I check that a relation exists ? And is there a way to do as I describe ?
Thank you
You can't replace relation like this, as what you intend is not logical - you want to retrieve relation that doesn't exist.
Instead you can do this:
public function getPriceAttribute()
{
return ($this->priceRelation) ?: $this->priceDefault();
}
public function priceDefault()
{
// edit: let's cache this one so you don't call the query everytime
// you want the price
return AppartmentPrice::remember(5)->find(0);
}
public function priceRelation()
{
return $this->hasOne('AppartementPrice');
}
Then you achieve what you wanted:
$app->price; // returns AppartmentPrice object related or default one
HOWEVER mind that you won't be able to work on the relation like normally:
$price = new AppartmentPrice([...]);
$app->price()->save($price); // will not work, instead use:
$app->priceRelation()->save($price);
First of all something really important in Laravel 4.
When you do not use parentheses when querying relationship it means you want to retreive a Collention of your Model.
You have to use parentheses if you want to continue your query.
Ex:
// for getting prices collection (if not hasOne). (look like AppartementPrice)
$appartment->price;
// for getting the query which will ask the DB to get all
//price attached to this appartment, and then you can continue querying
$priceQuery = $appartment->price();
// Or you can chain your query
$appartment->price()->where('price', '>', 0)->get() // or first() or count();
Secondly, your question.
//Appartement Model
// This function is needed to keep querying the DB
public function price()
{
return $this->hasOne('AppartementPrice')
}
// This one is for getting the appartment price, like you want to
public function getAppartmentPrice()
{
$price_object = $this->price;
if (!$price_object) // Appartment does not have any price {
return AppartementPrice->where('appartement_id', '=', 0)->get();
}
return $price_object;
}

How to check if a order has a shipment in Magento?

I need to check if an order has already some shipment set. The only data I can use is the increment id of the order. I'm getting an instance of a model order, but I don't see a way I can get a shipment instance.
I'm using this code:
$order = Mage::getModel('sales/order')
->loadByIncrementId($order_increment_id);
But how can I get a shipment instance? I know that I can call Mage::getModel('sales/order_shipment')->loadByIncrementId($shipment_increment_id) but how do I get the shipment increment id?
Assume that the person who wrote this might have also needed to do what you need to do. Generally, when Magento objects have a one to many relationship you can find a method to load the many on the one.
You've got a class alias sales/order.
This corresponds to Mage_Sales_Model_Order (in a stock installation).
You can find this class at app/code/core/Mage/Sales/Model/Order.php.
If you examine this class, there are 7 methods with the word "ship" in them
function canShip
function setShippingAddress
function getShippingAddress
function getShip
function getShipmentsCollection
function hasShip
function prepareShip
Of those 7, only the semantics of getShipmentsCollection indicate a method for grabbing an order's shipments. So try
foreach($order->getShipmentsCollection() as $shipment)
{
var_dump(get_class($shipment));
//var_dump($shipment->getData());
}
Or take a look at the source for getShipmentsCollection
public function getShipmentsCollection()
{
if (empty($this->_shipments)) {
if ($this->getId()) {
$this->_shipments = Mage::getResourceModel('sales/order_shipment_collection')
->setOrderFilter($this)
->load();
} else {
return false;
}
}
return $this->_shipments;
}
Just to make it complete Mage_Sales_Model_Order has public method:hasShipments()which returns number of shipments and internally uses mentioned getShipmentsCollection().

Resources