I have a class called shoppingCart and i would like to define an array inside of it. But it seems i need to manually create an instance of an array to use it. I am sure there is a way but i can`t find it
My shopping chart class
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Product;
class shoppingChart extends Model
{
var $products = Array();
var $productCount=0;
public function ItemCount(){
return count($products);
}
}
When i try to use i get a null pointer exceptionn and whenn i checked it $products doesn`t seem to be in variable list.
array_push($sc->products, "test");
I can do it as below. When i am using the array. Works fine.
public function addToBasket(Request $request)
{
$product = new Product();
$product->id = Input::get('product_id');
if($request->session()->has('shoppingCart')){
$sc = $request->session()->get('shoppingCart');
$sc->products = Array(); // If i remove this line code doesn`t work
array_push($sc->products,$product);
$sc->productCount=$sc->itemCount();
}
}
Should i initiate the array everytime i use it ? Doesn`t make any sense to me..
Without knowing more about the architecture of your application i can't go into specifics but I have a feeling that you might not even need this array.
If you are looking at a ShoppingCart has many Product's, then try using an eloquent "Many to Many" relationship using relationships \Illuminate\Database\Eloquent\Relations\HasMany.
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
By having this relationship you will be able to get all products related to you cart by going $cart->products which will return an eloquent Collection of the products associated with the cart.
Related
I know that association property in entity is implements \Doctrine\Common\Collections\Collection. I know that in constructor such properties should be initialized:
$this->collection = new \Doctrine\Common\Collections\ArrayCollection()
I know that I can modify collections using ArrayCollection#add() and ArrayCollection#remove(). However I have a different case.
Suppose I have a new simple array of associative entities. Using existing methods I need to check every element in array: if entity collection has it. If no - add array element to entity collection. In addition to this, I need to check every element in entity collection. If any collection element is absent in new array, then I need to remove it from collection. So much work to do trivial thing.
What I want? To have the setProducts method implemented:
class Entity {
private $products;
// ... constructor
public function setProducts(array $products)
{
// synchronize $products with $this->products
}
}
I tried: $this->products = new ArrayCollection($products). However this makes doctrine remove all products and add those ones from $products parameter. I want similar result but without database queries.
Is there any built in solution in Doctrine for such case?
Edit:
I would like to have a method in ArrayCollection like fromArray which would merge elements in collections removing unneeded. This would just duplicate using add/remove calls for each element in collection argumen manually.
Doctrine collections do not have a "merge"-feature that will add/remove entities from an array or Collection in another Collection.
If you want to "simplify" the manual merge process you describe using add/remove, you could use array_merge assuming both arrays are not numeric, but instead have some kind of unique key, e.g. the entity's spl_object_hash:
public function setProducts(array $products)
{
$this->products = new ArrayCollection(
array_merge(
array_combine(
array_map('spl_object_hash', $this->products->toArray()),
$this->products->toArray()
),
array_combine(
array_map('spl_object_hash', $products),
$products->toArray()
)
)
);
}
You might want to use the product id instead of spl_object_hash as 2 products with the same id, but created as separate entities - e.g. one through findBy() in Doctrine and one manually created with new Product() - will be recognized as 2 distinct products and might cause another insert-attempt.
Since you replace the original PersistentCollection holding your previously fetched products with a new ArrayCollection this might still result in unneeded queries or yield unexpected results when flushing the EntityManager, though. Not to mention, that this approach might be harder to read than explicitly calling addElement/removeElement on the original Collection instead.
I would approach it by creating my own collection class that extends Doctrine array collection class:
use Doctrine\Common\Collections\ArrayCollection;
class ProductCollection extends ArrayCollection
{
}
In the entity itself you would initialise it in the __constructor:
public function __construct()
{
$this->products = new ProductCollection();
}
Here, Doctrine will you use your collection class for product results. After this you could add your own function to deal with your special merge, perhaps something:
public function mergeProducts(ProductCollection $products): ProductCollection
{
$result = new ProductCollection();
foreach($products as $product) {
$add = true;
foreach($this->getIterator() as $p) {
if($product->getId() === $p->getId()) {
$result->add($product);
$add = false;
}
}
if($add) {
$result->add($product);
}
}
return $result;
}
It will return a brand new product collection, that you can replace your other collection in the entity. However, if the entity is attached and under doctrine control, this will render SQL at the other end, if you want to play with the entity without risking database updates you need to detach the entity:
$entityManager->detach($productEntity);
Hopes this helps
I've a very big doubt about how works laravel for a very simple thing:
If I call:
$companies=User::All();
Then I can use statement like this in a forach:
foreach($companies as $company)
$company['new_field']= 'something';
If i'm limiting the output of the query like:
$companies = DB::table('companies')
->select('id','name','email','business_name',...)->get();
The things doesnt work as before,
I try with or without the ->get()
I try to convert with ->toArray() (errors rised)
I try with put() and push() for collections method and agains errors...
How can I add a field in every item of the collection just to pass it to a view?
Try like this, hope it works for you:
$users=User::select('id','name','email','business_name',...)->get()->toArray();
and then use foreach loop like this:
foreach($users as $key => $value ){
$users[$key]['newField'] = "Demo";
}
If you are using Laravel and model in it so there is a better way to add custom attribute or field here is what i do for custom field
For Example :
There is a Model Name User
so in User Model
add a property name appends like :
class User extends Model
{
protected $appends = ['new_field'];
public function getNewFieldAttribute() // defining field logic here
{
return // your code
}
So you no need to use foreach and looping and adding new field
for more have a look on laravel doc : https://laravel.com/docs/5.5/eloquent-mutators#accessors-and-mutators
Suggestion
you can limit your output with Model too.
User::select('id','name','email','business_name',...)->get();
if you are making an array like
User::select('id','name','email','business_name',...)->get()->toArray();
so this will also give you your custom field
I am currently trying to make a function that calls different scopeQueries such as scopeByLocation() or scopeByPublished() on models defined in an array. I've got the basics working through [this link][1]. However, when trying to access custom made query scopes that are defined in the corresponding model, I get the following error: "Call to undefined method Illuminate\Database\Query\Builder::ForLocation($location)->get()".
What I want to achieve is a single method which loops through every model in the array of models and retrieves & calls the right scopeQuery on the model, something like this:
$modelElements = $model::{$queryScope}();
Where for example $model = 'Modules\News\Models\Article'
And $queryScope is a defined queryScope in the model itself. E.g. scopeForLocation($location).
I've tested $queryScope = 'all' and I get a result just fine, however when I try to access a custom queryScope ($queryScope = 'ForLocation($location)->get') that exists within for example the Location model, I get the following error: "Call to undefined method Illuminate\Database\Query\Builder::ForLocation($location)->get()".
So this all happens in a foreach-loop where every model in my models-array gets called and then the corresponding queryScope gets called on the model.
Why does the $queryScope = 'all' method works on my dynamic models, but other scopes throw an error? I really hope someone could help me get into the right direction with this issue.
Thanks in advance,
J. Doe.
Okay, I've finally solved it the following way:
//array of models
public function models()
{
return [
'Modules\Website\Models\Article',
...
];
}
//function that retrieves all elements for a model
public function getAllElementsForModel($model, $param)
{
//instantiate model
$model = new $model;
//call queryScope
//'queryScope' could be any queryScope that is defined within your model(s),
//the parameters are needed for the associated queryScope
$query = call_user_func_array([$model, 'queryScope'], [$param1, $param2]);
$result = $query->get();
//do stuff with your $result
}
//retrieves all
public function all($param)
{
//loop through the array of models
foreach($this->models() as $model){
$this->getAllElementsForModel($model, $param);
//do stuff here...
}
}
Sharing is caring!
I would like to know how it is possible to merge data from Input::all() with a model and save the result.
To clarify: I would like to do something like below:
$product = Product::find(1); // Eloquent Model
$product->merge( Input::all() ); // This is what I am looking for :)
$product->save();
You should use update method:
$product->update(Input::all());
But I recommend to use only method instead
$product->update(Input::only('name', 'type...'));
Use the model's fill() method for greater control. This lets us change attributes after merging the values before we save:
$product->fill($request->all());
$product->foo = 'bar';
$product->save();
If we've properly defined the model's $fillable attributes, there's no need to use Input::only(...) (or $request->only(...) in newer versions).
In addition to Razor's answer, if you need to create a new model you can use:
$product = Product::create(Input::all());
I think the better way now is to use FormRequest and the validated function like this :
public function update(Product $product, ProductFormRequest $request)
{
$product->update($request->validated());
//...
}
As I am required to pirnt the ratings of products in JSON format, i have made a module with controller and rating.php file in model folder. We I run the controller it shows all the data from that table, But I required only a single row. So through the url i am passing a parameter, but it wont works. I am attaching my indexcontroller.php here. suggest me upon this.
<?php
class Modulename_CustomRating_IndexController extends Mage_Core_Controller_Front_Action
{
public function indexAction ()
{
$arrParams = $this->getRequest()->getParams();
var_dump($arrParams);
$collection = Mage::getModel('Modulename_CustomRating_Model_CustomRating')->getCollection();
}
print_r (json_encode($collection ->getData()));
}
}
?>
As I am passing url as:localhost/magento/customrating?vote_id=1 , it is taking the parameter to it but returns whole table's data. I know this is due to getData(); but how to make to get the required row?
You have to use setEntityPkFilter method. Check Mage_Rating_Model_Resource_Rating_Option_Vote_Collection class for other methods.
$product_id = $this->getRequest()->getParam('product_id'); // or 'vote_id'
$collection = Mage::getModel('Modulename_CustomRating_Model_CustomRating')
->getResourceCollection()
->setEntityPkFilter($product_id);
If you want only 1 column you can try some Zend stuff because you can't use addAttributeToSelect. getSelect() returns Zend like query:
$adapter = $this->getConnection(); // $this->getConnection();
$collection->getSelect()
->reset(Zend_Db_Select::COLUMNS) // remove all columns
->columns('attribute_name'); // add only needed one
$result = $adapter->fetchAll($select);
Not sure whether this would work. It's not tested, just an idea.