How to send data from different controllers/actions to the same view? - laravel

This is my first experience with Laravel, and so far I'm having some difficulties passing data to views. My app is a single page website with one menu on the top listing all the product categories and below there is a grid of thumbnails for each item or product. Visitors are able to filter the products by their category of choice.
Route::get('home/{category}', array('as'=>'itemshome', 'uses'=>'ItemsController#index'));
So in my ItemsControllers I fetch some items from the item model and pass them to the view.
class ItemsController extends \BaseController {
public function index($category)
{
return View::make('home/index', ['items' => Item::where('publishtime', '<',
date('Y-m-d H:i:s'))->where('category_id','=',$category)->paginate(24)]);
}
At this point I'm not sure if I should send data from the Category model to the home view using the ItemsController, or if it would it be a better approach to define a new CategoryController and pass the values from there.

You can't just use another controller to send data to the same view during the same request.
Either add it to the view make call:
return View::make('home/index', [
'items' => Item::where('publishtime', '<', date('Y-m-d H:i:s'))->where('category_id','=',$category)->paginate(24),
'categories' => Category::all()
];
Or, if the category data actually has nothing to do with the items controller but is needed by the view, you could register a view composer
View::composer('home/index', function($view){
$view->with('categories', Category::all());
});
Now every time when the home/index view gets rendered, categories will be injected.
You can actually place the view composer anywhere you want. However I recommend you add a new file app/composers.php to store all your view composers. Then you need to include it somewhere. For example in app/start/global.php at the bottom:
require app_path().'/composers.php';

Related

Backpack for Laravel: how to add 'delete' per-line button conditionally?

I've a parent model which can have n childs
So I want to show delete button ONLY if it has not children (hasMany relationship must return 0 records).
How can I show 'delete' link in each lines of a table (in the list operation), but ONLY if a condition is valid?
The easiest option I see is to use a custom view for the Delete button, instead of the one in the package. Depending on how wide you want this change to be made:
A. If you want to do that across all CRUDs - it's easy, just publish the view by running:
php artisan backpack:publish crud/buttons/delete
This will place the file in your resources/views/vendor/backpack/crud/buttons, for you to change however you like. Inside the delete button view you have the current entry available as $entry so you can do something like $entry->children()->count() if you want. Be mindful that this will be run ONCE PER LINE so if you show 50 lines in the table for example, you'd need to find a way to optimize this.
B. If you want to do that for just one CRUD (eg. do it for Categories but not for Products), then you can do the same thing (publish the button view), but rename the button to something different like delete_if_no_children.blade.php so that it doesn't get used automatically for all CRUDs. Then use it only inside the controllers you want, inside setupListOperation(), by removing the "stock" delete button and adding yours:
// using the Backpack array syntax
$this->crud->removeButton('delete');
$this->crud->addButton('line', 'delete', 'view', 'crud::buttons.delete_if_no_children', 'end');
// using the Backpack fluent syntax
CRUD::button('delete')->view('crud::buttons.delete_if_no_children');
Use
withCount('children')
Docs: withCount
Additionally you can wrap delete buttons with blade directive
#can('destroy', $model) disabled #endcan
Docs: #can
<?php
namespace App\Policies;
use App\Models\Model;
use App\Models\User;
class ModelPolicy
{
public function update(User $user, Model $model)
{
return $model->children_count === 0;
}
}
Docs: policy
A hasMany relationship will return an empty Collection when there are no associated records. You can then proceed to call isEmpty() on the collection to verify there are no child records (children).
Example in PHP:
$parents = Parent::with('children')->get();
And then in your template you can do:
#foreach($parents as $parent)
#if($parent->children->isEmpty())
<button>Delete</button>
#endif
#endforeach

Laravel - Authorize with other policy

I have a gallery policy and a photo policy, a gallery controller, and a photo controller.
It works like this:
user-> hasMany galleries -> hasMany photos
I do have a photo upload page (with dropzone), that uses the photo controller.
the url is like this: /gallery/3/upload
I want to restrict access to this page only if the user is the owner of the gallery 3. But this page uses the PhotoPolicy, that makes use of the Photo model, not the Gallery model.
How can I authorize this page, using the GalleryPolicy instead of the PhotoPolicy? Or do I have to copy over the view method from the GalleryPolicy and have it also in the PhotoPolicy?
EDIT:
I do not understand this...
In my PhotoPolicy:
public function view(User $user, Photo $photo)
{
return false;
}
In my Photos controller:
$this->authorize('view', $photo);
In my AuthenticationServiceProvider:
protected $policies = [
\App\Gallery::class => \App\Policies\GalleryPolicy::class,
\App\Photo::class => \App\Policies\PhotoPolicy::class,
];
Restult: page loads just fine.. even if return is false.. why?
You can authorize this page in PhotoPolicy in create method, because you have just one way to upload images which is also using this url.
In PhotoPolicy you have gallery's id which it was passed as params, so you can check owner of gallery and restrict them.
And another point is according to API rules it's better change upload's url to gallery/3/photos.

How to pass value from one controller to two or more view in laravel 5.4

I m working on a e commerce site with laravel 5.4
Let's assume I have a ProductConttoller and inside a showSingle($id) function.
I want pass value to the view of single product view with product details and wanna also pass the product title to a partial view _meta.blade.php
For single product view I am passing product value like
return view('product.show')->with product($product);
Now how to pass title/any meta to a different view like meta.blade.php
Thank you
I'm guessing that you use the include function in your single product view.
So just do like that:
#include('_meta', ['title' => $product->title])
Or probably more easier, pass the entier product:
#include('_meta', ['product' => $product])
Then you can access any product properties from your _meta template.

Joomla MVC Module delete model

I'm a newbie on Joomla developing and I'm trying to fix an old administration module made by 'someone before me'. Module's been developed using MVC Components, it has several CRUDs and I'm stucked at deleting an item. The template view adds the toolbar icon like this:
JToolbarHelper::deleteList('', 'paises.delete', JTOOLBAR_DELETE);
It also has at the list controller (DistribuidoresControllerPaises), the getModel function:
public function getModel($name = 'Pais', $prefix = 'DistribuidoresModel', $config = array('ignore_request' => true))
{
$model = parent::getModel($name, $prefix, $config);
return $model;
}
The model class:
class DistribuidoresModelPais extends JModelAdmin
When selecting an item on the list, and clicking the trash button an empty page opens with this ending:
administrator/index.php?option=com_distribuidores&view=pais
If I come back to grid, the item still remains.
Any suggestion?
Thanks in advance
You can debug this by enabling debugging from Joomla configuration or you can try to to check with exit with in "delete" function of "paises" controller and can check you get item ids in post request or not.
Also you are using view "pais" also using model "pais" then why you are using "paises" controller for delete function, you should use "pais" controller to delete.
Also provide delete function which you are using to delete items, it may contain some issue.

Is it good practice to add own file in lib/Varien/Data/Form/Element folder

I need to create module in Magento which will have few database tables. One of the function of the module is adding multiple images.
For example while being on the "Add new item" or "Edit item" page in the admin, from the left side I have tabs, one of them is "Item Images". When being clicked I want the content of this tab to be my own custom one.
After digging into the code, found out that the way it renders this content, Magento is using one of the Varien_Data_Form_Element classes for each element in the full form. I want to add my own class here that will render form elements the way I want.
Is this a good practice to do so, or there is some other more elegant way of adding own content in the admin forms?
EDIT: I must add that none of the existing classes is helping my problem.
SOLUTION EDIT:
I have a controller in my custom module that is in Mypackage/Mymodule/controllers/Adminhtml/Item.php. In the editAction() method which I am using for adding and creating new items, I am creating 2 blocks, one for the form and one left for the tabs:
$this->_addContent($this->getLayout()->createBlock('item/adminhtml_edit'))
->_addLeft($this->getLayout()->createBlock('item/adminhtml_edit_tabs'));
$this->renderLayout();
The Block/Adminhtml/Edit/Tabs.php block is creating 2 tabs on the left: General Info and Item Images, each of them are rendering different content on the right side using Block classes.
protected function _beforeToHtml()
{
$this->addTab('item_info', array(
'label' => Mage::helper('mymodule')->__('Item Info'),
'content'=> $this->getLayout()->createBlock('item/adminhtml_edit_tab_form')->toHtml(),
));
$this->addTab('item_images', array(
'label' => Mage::helper('mymodule')->__('Item Images'),
'active' => ( $this->getRequest()->getParam('tab') == 'item_images' ) ? true : false,
'content' => $this->getLayout()->createBlock('item/adminhtml_images')->toHtml(),
));
return parent::_beforeToHtml();
}
I wanted the tab item_images to render my own form elements and values, not the default varien form elements.
class Mypackage_Mymodule_Block_Adminhtml_Images extends Mage_Core_Block_Template
{
public function __construct()
{
parent::__construct();
$this->setTemplate('item/images.phtml'); //This is in adminhtml design
}
public function getPostId()
{
return $this->getRequest()->getParam('id');
}
public function getExistingImages()
{
return Mage::getModel('mymodule/item')->getImages($this->getPostId());
}
}
Then in the template app/design/adminhtml/default/default/template/item/images.phtml you can use these values:
//You can add your own custom form fields here and all of them will be included in the form
foreach($this->getExistingImages() as $_img):
//Do something with each image
endforeach;
//You can add your own custom form fields here and all of them will be included in the form
No, it's not. You should never edit or add to files that provided by a vendor. If you absolutely must replace a class file you should use the local code pool. For example, if you wanted to change the behavior of a text field,
lib/Varien/Data/Form/Element/Text.php
You should place a file in the local or community code pool
app/code/local/Varient/Data/Form/Element/Text.php
However, doing the replaces the class, and it becomes your responsibility to maintain compatibility with future versions. That means if Magento Inc. changes lib/Varien/Data/Form/Element/Text.php, you need to update your version to be compatible.
Based on what you said I'd look into creating a class rewrite for the Block class that renders the form.

Resources