I am using Laravel for controller and blade file for a webpage. My code is something like:
PropertiesController
$properties = Property::where('status', 1);
$properties = $properties->orderBy('properties.created_at', 'DESC')->paginate(8);
return view('properties.index')->with('properties', $properties);
in index.blade.php
#foreach ($properties as $property)
<div class="geo">
<span class="lat">{{ $property->title }}</span>,
<span class="lng">{{ $property->description }}</span>
</div>
what I want to achieve is to get categories w.r.t. counts along with properties, for that, I am doing
$properties = Property::where('status', 1);
$categories = array();
if (is_null($req->c)) {
$search = $properties;
foreach (Category::all() as $category) {
array_push(
$categories,
array(
'id' => $category->id,
'name' => $category->category,
'counts' => count($search->where('properties.category', $category->id)->get()),
)
);
}
}
$properties = $properties->orderBy('properties.created_at', 'DESC')->paginate(8);
return view('properties.index')->with('properties', $properties)->with('categories', $categories);
$search = $properties; and
'counts' => count($search->where('properties.category', $category->id)->get()),
with this it gives me
Trying to get property of non-object
<span class="lat"><?php echo e($property->title); ?></span>,
What I think is you want to pass your data to blade view and get counts of categorized data with each category... For that, you can use duplicated functions to count your data separately. e.g.:
public function properties() {
$properties = Property::where('status', 1);
$categories = array();
foreach (Category::all() as $category) {
$count = $this->count($category->id);
array_push(
$categories,
array(
'id' => $category->id,
'name' => $category->category,
'counts' => $count,
)
);
}
$properties = $properties->orderBy('properties.created_at', 'DESC')->paginate(8);
return view('properties.index')->with('properties', $properties)->with('categories', $categories);
}
public function count($id) {
$count = count(Property::where('category_id', $id)); // or any variable you are using to connect categories table with
return $count;
}
$count = $this->count($category->id);
This is the line which did the trick.
If the relationships are made in the models you should only use with () in this way.
This is how the controller should be.
$properties = Property::where('status', 1)->with('category')->orderBy('properties.created_at', 'DESC')->paginate(8);
return view('properties.index', compact('propierties'));
This will give you the list of Properties next to the assigned category.
But if you need to list the categories and have in each category the properties you must do this.
$categories = Category::with('properties')->paginate(8);
return view('properties.index', compact('categories'));
Related
I have a problem wanting to pass the id of Products in the subqueries.
The first code is what I have so far. The second is the way I want to do with Eloquent, but I can't.
$result = [];
Product::with(['locals.presentations'])->each(function ($product) use (&$result) {
$body['id'] = $product->id;
$body['nombre'] = $product->nombre;
$sedes = [];
$product->locals->each(function ($local) use (&$sedes, $product) {
$presentations = [];
$local->presentations->each(function ($presentation) use (&$presentations, $local, $product) {
if ($presentation->local_id == $local->id && $presentation->product_id == $product->id) {
$presentations[] = [
'local_id' => $presentation->local_id,
'product_id' => $presentation->product_id,
'presentacion' => $presentation->presentation,
'precio_default' => $presentation->price
];
}
});
...
});
return $result;
I want transform the previous code into this with Eloquent, but I can't pass the product_id into the subqueries:
$products = Product::with(['locals' => function ($locals) {
//How to get the id from Product to pass in the $presentations query ??????
$locals->select('locals.id', 'descripcion')
->with(['presentations' => function ($presentations) {
$presentations
// ->where('presentations.product_id', $product_id?????)
->select(
'presentations.local_id',
'presentations.product_id',
'presentations.id',
'presentation',
'price'
);
}]);
}])->select('products.id', 'nombre')->get();
return $products;
Product
public function locals()
{
return $this->belongsToMany(Local::class)->using(LocalProduct::class)
->withPivot(['id', 'is_active'])
->withTimestamps();
}
Local
public function presentations()
{
return $this->hasManyThrough(
Presentation::class,
LocalProduct::class,
'local_id',
'local_product_id'
);
}
You can simply use the has() method if you have set the relations correctly on the Product and Local models. This will return ONLY the products which has locals AND presentations.
If you want every product but only the locals and presentations with the product_id equals to the products.id, then you don't have to do anything. The relationship you set in your models already checks if the id matches.
$products = Product::has('locals.presentations')
->with(['locals' => function ($locals) {
$locals
->select('locals.id', 'descripcion')
->with(['presentations' => function ($presentations) {
$presentations->select(
'presentations.local_id',
'presentations.product_id',
'presentations.id',
'presentation',
'price'
);
}]);
}])->select('products.id', 'nombre')->get();
How do I get a model from the database and then convert it to an Array including extra information using the with statement.
public function edit($id) {
// convert product to array;
$product = Product::findOrFail($id)->with('supplier', 'category');
$data = [
'suppliers' => Supplier::all()->pluck('company', 'id'),
];
// cannot merge because $product is object and cannot turn into array
// the only way I know to convert to array is doing this
// $product->first()->toArray() but this gets the first item in the database
$product = array_merge($product, $data);
return response()->json($product, 200, ['Content-Length' => strlen(json_encode($product))]);
}
You could use Laravel's collection helper to make it simple:
collect($product)->toArray()
Then you should be able to do:
$product array_merge(collect($product)->toArray(), $data);
What about this:
$return = [
'suppliers' => Supplier::all()->pluck('company', 'id'),
'product' => $product // or $product->toArray()
];
return response()->json($return, 200);
If you need the suppliers to be an attribute of the product, you could try this:
$productArr = $product->toArray();
$productArr['suppliers'] = Supplier::all()->pluck('company', 'id');
return response()->json($productArr, 200);
I am adding a mass action to add a category. I am most of the way there I only have one function left to figure out.
Clr\Categorymassaction\controllers\Adminhtml\Catalog\ProductController.php
class Clr_Categorymassaction_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller_Action
{
public function massCategoryAction()
{
$productIds = $this->getRequest()->getParam('product');
$cat = $this->getRequest()->getParam('Category');
if (!is_array($productIds)) {
$this->_getSession()->addError($this->__('Please select product(s).'));
$this->_redirect('*/*/index');
}
else {
$cat = $category['label']->getCategoryId();
foreach($productIds as $product) {
//Process $cat into categoryId append categoryId to $productId
$cat->setPostedProducts($product);
}
//Save product
$cat->save();
}
}
}
Clr\Categorymassaction\Model\Observer
class Clr_Categorymassaction_Model_Observer {
public function addCategoryMassAction(Varien_Event_Observer $observer)
{
$block = $observer ->getBlock();
if ($block instanceof Mage_Adminhtml_Block_Catalog_Product_Grid) {
$block->getMassactionBlock()->addItem('Clr_Categorymassaction', array(
'label' => Mage::helper('catalog')->__('Add to Category'),
'url' => $block->getUrl('*/*/massCategory', array('_current' => true)),
'additional'=> array(
'visibility' => array(
'name' =>'Category',
'class' =>'required-entry',
'label' =>Mage::helper('catalog')->__('Categories'),
'type' => 'select',
'values' => Mage::getModel('Categorymassaction/system_config_source_category')->toOptionArray(),
'renderer' => 'Categorymassaction/catalog_product_grid_render_category',
)
)
));
};
}
}
One last thing
class Clr_Categorymassaction_Model_System_Config_Source_Category
{
public function toOptionArray($addEmpty = true)
{
$options = array();
foreach ($this->load_tree() as $category) {
$options[$category['value']] = $category['label'];
}
return $options;
}
I am mostly in trouble here because I am refactoring, Flagbit_changeattributeset and Vuleticd_AdminGridCategoryFilter. I know what I need to do (at least I think I do) I just don't know how to finish this off. Thanks for your eyes and ears if you read it all.
UPDATE: The observer from Vuleticd_AdminGridCategoryFilter had this additional code
'filter_condition_callback' => array($this, 'filterCallback'),
)
)
));
};
}
public function filterCallback($collection, $column)
{
$value = $column->getFilter()->getValue();
$_category = Mage::getModel('catalog/category')->load($value);
$collection->addCategoryFilter($_category);
return $collection;
}
This was used to apply the filter to the grid. What I am trying to do is instead of using the dropdown to filter column fields; use the dropdown to trigger the ProductController to pass the selected items a new categoryid.
https://magento.stackexchange.com/questions/67234/productcontroller-for-mass-action Asked this question over at magento's stackexchange figured I would post the link here for posterity.
This should be a simple passing an array to a view. The controller is set to pull all data from the table. I have initialized the table library and loaded the model code with the $this->load->model(array('Account'). I have full crud methods built.
I am getting a variable undefined on my view page.
Controller code is:
public function index(){
$this->load->library('table');
$children = array();
$this->load->model(array('Account'));
$children = $this->Account->get(); //retrieves all the records in the database
foreach ($children as $child){
$account = new Account();
$account->load($account->id);
$children[] = array(
$account->id,
$account->familyName,
$account->addr1,
$account->city,
$account->state,
$account->zip,
$account->phone1,
$account->email,
$account->parent_only,
);
}
$this->load->view('main_view');
$this->load->view('body_content_ma', array(
'body_content_ma' => $children,
));
}
On the view page I get an error that says undefined variable children. What do you think I am missing here:
View code is:
<?php
$this->table->set_heading('ID', 'Family Name', 'City', 'State', 'Zip', 'Phone', 'Email', 'Parent only Pickup');
echo $this->table->generate($children);
?>
ANSWER:
This is the coding that finally worked.
I had to go back through it a few times to get it what was missing.
public function index(){
$this->load->library('table');
$children = array();
$this->load->model(array('Account'));
$account = $this->Account->get(); //retrieves all the records in the database
foreach ($account as $c){
$account = new Account();
$account->load($account->id);
$children[] = array(
$c->id,
$c->familyName,
$c->addr1,
$c->city,
$c->state,
$c->zip,
$c->phone1,
$c->email,
$c->parent_only,
);
}
//echo '<tt><pre>' . var_export($children, TRUE) . '</pre></tt>';
$this->load->view('main_view');
$this->load->view('body_content_ma', array(
'body_content_ma' => $children
));
}
I had a feeling that I was using $children to many times and was overwriting the variable. I was right. Once I declared the variable. I should not have used it again.
When I reassigned the variable $children to $children = $this->Account->get();
I think I effectively overwrote the array that was declared the line before. So even though the array was filled the array reference was destroyed.
I did use the $body_content_ma in the view code to generate the table.
Everything is being rendered now.
On to pagination!
just simple things you are missing $children variable is mapped to $body_content_ma
just replace $children to $body_content_ma .
echo $this->table->generate($children);
replace by
echo $this->table->generate($body_content_ma );
you can use this code.. hope will be working for you.
public function index(){
$this->load->library('table');
$children = array();
$this->load->model(array('Account'));
$data['children'] = $this->Account->get(); //retrieves all the records in the database
$this->load->view('main_view');
$this->load->view('body_content_ma',$data));
}
in view you can use $children as a array to print the value.
This would be my function;
public function index()
{
$this->load->library('table');
$this->load->model('Account_model');
$data['children'] = $this->Account_model->get();
foreach ($data['children'] as $child)
{
// Your foreach code...
}
$this->load->view('main_view');
$this->load->view('body_content_ma', $data);
}
Your view:
<?php
$this->table->set_heading('ID',
'Family Name',
'City',
'State',
'Zip',
'Phone',
'Email',
'Parent only Pickup');
echo $this->table->generate($body_content_ma);
?>
Explanation:
You are passsing body_content_ma from your controller to your view and not children hence giving you an undefined error.
Edit:
Below is the format of the array to generate rows of the table.
The array should consist of array of rows.
$data = array(
array('Name', 'Color', 'Size'),
array('Fred', 'Blue', 'Small'),
array('Mary', 'Red', 'Large'),
array('John', 'Green', 'Medium')
);
echo $this->table->generate($data);
Documentation: http://ellislab.com/codeigniter/user-guide/libraries/table.html
I am using MySQL as the database connection adapter for all my models. I have a downloads model and controller with an index function that renders either an HTML table or a CSV file depending on the type passed from the request. I also have a CSV media type to handle an array of data, which is working as expected (outputs array keys as headers then array values for each row of data).
I wish to do the same find query but then remove ID fields from the record set if a CSV file is going to be rendered. You'll notice that the download ID is being fetched even though it is not in the fields array, so simply changing the fields array based on the request type will not work.
I have tried the following in the index action of my downloads controller:
<?php
namespace app\controllers;
use app\models\Downloads;
class DownloadsController extends \lithium\action\Controller {
public function index() {
// Dynamic conditions
$conditions = array(...);
$downloads = Downloads::find('all', array(
'fields' => array('user_id', 'Surveys.name'),
'conditions' => $conditions,
'with' => 'Surveys',
'order' => array('created' => 'desc')
));
if ($this->request->params['type'] == 'csv') {
$downloads->each(function ($download) {
// THIS DOES NOT WORK
unset($download->id, $download->user_id);
// I HAVE TRIED THIS HERE AND THE ID FIELDS STILL EXIST
// var_dump($download->data());
// exit;
return $download;
});
return $this->render(array('csv' => $downloads->to('array')));
}
return compact('downloads');
}
}
?>
I thought there was an __unset() magic method on the entity object that would be called when you call the standard PHP unset() function on an entity's field.
It would be great if there was a $recordSet->removeField('field') function, but I can not find one.
Any help would be greatly appreciated.
Perhaps you should do $downloads = $downloads->to('array');, iterate the array with a for loop, remove those fields from each row, then return that array. If you have to do this same thing for a lot of actions, you could setup a custom Media handler that could alter the data without needing logic for it in your controller.
Take a look at this example in the Lithium Media class unit test.
You can also avoid having much logic for it in your controller at all through the use of a custom handler. This example also auto-generates a header row from the keys in your data.
In config/bootstrap/media.php:
Media::type('csv', 'application/csv', array(
'encode' => function($data, $handler, $response) {
$request = $handler['request'];
$privateKeys = null;
if ($request->privateKeys) {
$privateKeys = array_fill_keys($request->privateKeys, true);
}
// assuming your csv data is the first key in
// the template data and the first row keys names
// can be used as headers
$data = current($data);
$row = (array) current($data);
if ($privateKeys) {
$row = array_diff_key($row, $privateKeys);
}
$headers = array_keys($row);
ob_start();
$out = fopen('php://output', 'w');
fputcsv($out, $headers);
foreach ($data as $record) {
if (!is_array($record)) {
$record = (array) $record;
}
if ($privateKeys) {
$record = array_diff_key($record, $privateKeys);
}
fputcsv($out, $record);
}
fclose($out);
return ob_get_clean();
}
));
Your controller:
<?php
namespace app\controllers;
use app\models\Downloads;
class DownloadsController extends \lithium\action\Controller {
public function index() {
$this->request->privateKeys = array('id', 'user_id');
// Dynamic conditions
$conditions = array(...);
$downloads = Downloads::find('all', array(
'fields' => array('user_id', 'Surveys.name'),
'conditions' => $conditions,
'with' => 'Surveys',
'order' => array('created' => 'desc')
));
return compact('downloads');
}
}
?>
Why not then just dynamically set your $fields array?
public function index() {
$type = $this->request->params['type'];
//Exclude `user_id` if request type is CSV
$fields = $type == 'csv' ? array('Surveys.name') : array('user_id', 'Surveys.name');
$conditions = array(...);
$with = array('Surveys');
$order = array('created' => 'desc');
$downloads = Downloads::find('all', compact('conditions', 'fields', 'with', 'order'));
//Return different render type if CSV
return $type == 'csv' ? $this->render(array('csv' => $downloads->data())) : compact('downloads');
}
You can see in this example how I send the array for your CSV handler, otherwise it's the $downloads RecordSet object that goes to the view.