Hello I'm new to laravel but not php. I was tasked to optimized some backend query and needed some help on locating where the model function "getPackagesSoldAttribute" is being called here. I don't see in the controller that this function is being called like ProEvent::getPackagesSoldAttribute for example.
So my view is showing the return of the function. Any idea how did laravel called this function? I also did check PHP DebugBar and I saw the query the getPackagesSoldAttribute function used.
I also created a script that would locate the string "getPackagesSoldAttribute" but could only find one and that is in the model.
Route::get('{organiser_id}/pro_events/{filter?}', [
'as' => 'showOrganiserProEvents',
'uses' => 'OrganiserProEventsController#showOrganiserProEvents',
]);
This is the controller function called by route.
public function showOrganiserProEvents(Request $request, $organiser_id, $filter = null, $listView = null)
{
$add_on_check = \App\Models\OrganisationAddon::where('org_id', $organiser_id)->first();
$edit_create_enable = "";
$delete_enable = "";
if( !empty($add_on_check) ){
$add_ons = json_decode($add_on_check->add_ons);
$edit_create_enable = !empty($add_ons->enable_create_edit_event)?"1":"";
$delete_enable = !empty($add_ons->enable_delete_event)?"1":"";
}
$organiser = Organiser::find($organiser_id);
$allowed_sorts = ['created_at', 'event_date', 'title'];
$searchQuery = $request->get('q');
$sort_by = (in_array($request->get('sort_by'), $allowed_sorts) ? $request->get('sort_by') : 'event_date');
$eventListView = empty($request->get('view_list_by')) ? 'grid' : $request->get('view_list_by');
if($listView){
$eventListView = $listView;
}
if($filter == null){
$filter = "live";
}
if( $searchQuery ){
$the_event = ProEvent::where('title', 'like', '%' . $searchQuery . '%');
if($sort_by == 'event_date'){
$the_event->orderBy($sort_by, 'asc');
} else {
$the_event->orderBy($sort_by, 'desc');
}
$the_event->where('organiser_id', '=', $organiser_id);
if( $filter == "templates"){
$the_event->where(function($query){
$query->where('event_status', 'template');
$query->orWhere('is_master', 1);
});
}else if( $filter == "live" ){
$the_event->where('event_status', "live");
}else if( $filter == "past" ){
$the_event->where(function($query){
$query->where('event_status', 'past');
$query->orWhere('event_date', '<', Carbon::now());
});
}else if( $filter == "testing" ){
$the_event->where(function($query){
$query->where('event_status', 'testing');
$query->orWhere('event_status', 'pos_testing');
});
}else if( $filter == "abandoned" ){
$the_event->where('event_status', "abandoned");
}
$events = $the_event->get();
}else{
$the_event = ProEvent::where('organiser_id', '=', $organiser_id);
if($sort_by == 'event_date'){
$the_event->orderBy($sort_by, 'asc');
} else {
$the_event->orderBy($sort_by, 'desc');
}
if( $filter == "templates"){
$the_event->where(function($query){
$query->where('event_status', 'template');
$query->orWhere('is_master', 1);
});
}else if( $filter == "live" ){
$the_event->where('event_status', "live");
}else if( $filter == "past" ){
$the_event->where(function($query){
$query->where('event_status', 'past');
$query->orWhere('event_date', '<', Carbon::now());
});
}else if( $filter == "testing" ){
$the_event->where(function($query){
$query->where('event_status', 'testing');
$query->orWhere('event_status', 'pos_testing');
});
}else if( $filter == "abandoned" ){
$the_event->where('event_status', "abandoned");
}
$events = $the_event->get();
}
$data = [
'event_types' => $organiser->pro_event_types,
'events' => $events,
'organiser' => $organiser,
'search' => [
'q' => $searchQuery ? $searchQuery : '',
'sort_by' => $request->get('sort_by') ? $request->get('sort_by') : '',
'showPast' => $request->get('past'),
],
'edit_create_enable' => $edit_create_enable,
'delete_enable' => $delete_enable,
'filter' => $filter,
'eventListView' => $eventListView
];
return view('ManageEmsPro.ProEvents', $data);
}
This is the model
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Session;
use Str;
use URL;
use Illuminate\Http\UploadedFile;
use File;
use Image;
use Log;
use Storage;
class ProEvent extends MyBaseModel
{
use SoftDeletes;
protected $table = 'pro_events';
protected $appends = array('packages_sold', 'bundles_sold');
/**
* The validation rules.
*
* #var array $rules
*/
protected $rules = [
'information_link' => ['regex:/^(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/'],
'redirect_link_url' => ['regex:/^(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/'],
'web_sales_start_date' => ['required'],
'sales_start_date' => ['required'],
'open_time' => ['required'],
'close_time' => ['required'],
'title' => ['required'],
'description' => ['required'],
'event_date' => ['required'],
'organiser_name' => ['required_without:organiser_id'],
'event_image' => ['mimes:jpeg,jpg,png', 'max:3000'],
'custom_url' => ['regex:/(^[\w\d_-]+$)/u'],
'payment_percentage' => ['numeric', 'between:0,99.99', 'min:1'],
'event_logo' => ['mimes:jpeg,jpg,png', 'max:1000'],
'organiser_event_logo' => ['mimes:jpeg,jpg,png', 'max:1000'],
];
/**
* The validation error messages.
*
* #var array $messages
*/
protected $messages = [
'title.required' => 'You must at least give a title for your event.',
'organiser_name.required_without' => 'Please create an organiser or select an existing organiser.',
'event_image.mimes' => 'Please ensure you are uploading an image (JPG, PNG, JPEG)',
'event_image.max' => 'Please ensure the image is not larger then 3MB',
'custom_url.regex' => 'Allowed special characters are only "_" and "-"',
'event_logo.mimes' => 'Please ensure you are uploading an image (JPG, PNG, JPEG)',
'event_logo.max' => 'Please ensure the image is not larger then 1MB',
];
...
public function getPackagesSoldAttribute(){
$valid_packages = PackageInventoryMap::where("pro_event_id", $this->id)->pluck('package_id');
$valid_orders = ProOrders::whereNotIn("order_status_id", [2,4])->where("organiser_id", $this->organiser_id)->pluck('id');
$pro_order_items = ProOrderItem::whereIn('pro_order_id', $valid_orders)
->where("pro_event_id", $this->id)
->whereIn('package_id', $valid_packages)
->whereNull("bundle_ids")
->sum('quantity');
return (integer)$pro_order_items;
}
...
This is part of the view.
<div class="row">
#if($events->count())
#if($eventListView == "grid")
<div class="col-sm-12 grid-search">
<div class="col-sm-offset-6 col-sm-6">
<div class="pull-right lh-2">
Search: <input class="form-control pull-right input-sm grid-filter">
</div>
</div>
</div>
#foreach($events as $key => $event)
<div class="col-md-6 col-sm-6 col-xs-12 data-event-block" data-event-block="{{ $key+1 }}" style="display: {{ $key <= 9 ? 'block' : 'none' }}">
#include('ManageEmsPro.Partials.EventPanel')
</div>
#endforeach
#elseif($eventListView == "table")
<div class="col-md-12">
#include('ManageEmsPro.Partials.EventTable')
</div>
#endif
#else
#if($search['q'])
#include('Shared.Partials.NoSearchResults')
#else
#include('ManageEmsPro.Partials.EventsBlankSlate')
#endif
#endif
</div>
See Eloquent: Mutators. getPackagesSoldAttribute is an "Accessor" method. Basically, you wont see getPackagesSoldAttribute called directly, instead, when the code calls $model->packages_sold, in the background, laravel will actually call $model->getPackagesSoldAttribute dynamically and return its response as that value.
For example, if you wanted to debug or test this method, you might do something like:
$event = ProEvent::find($someId);
$packagesSold = $event->packages_sold; // this line will call the `getPackagesSoldAttribute` and set `$packagesSold` to the value it returns.
Also of note:
The model here also defines an appends property with packages_sold
protected $appends = array('packages_sold', 'bundles_sold');
This will cause the packages_sold property to be automatically filled by the method in question any time the model is represented as an array or serialized. see also
Appending Values To JSON
Related
This is my banners structure in home page :
As you can see I have 4 section for banners - small banners | medium banners | news banners | large banners
And I have one model called Banner , 4 controllers to manage this banners and 4 tables to save data.
This is Banner model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Banner extends Model
{
protected $fillable = [
'title', 'image', 'url', 'image_title', 'image_alt'
];
}
And Controllers :
SmallController :
class SmallController extends Controller
{
public function small_list()
{
$smallBanners = DB::table('small_banner')->get();
return view('admin.banners.small.list', compact('smallBanners'));
}
public function small_create()
{
return view('admin.banners.small.add');
}
public function small_store(Request $request)
{
$data = $request->validate([
'title' => 'required',
'url' => 'required',
'image' => 'required',
'image_title' => 'max:255',
'image_alt' => 'max:255'
]);
DB::table('small_banner')->insert($data);
return redirect(route('admin.banners.small.index'));
}
public function small_edit($id)
{
$small = DB::table('small_banner')->where('id', $id)->first();
return view('admin.banners.small.edit', compact('small'));
}
public function small_update(Request $request, $id)
{
$small = DB::table('small_banner')->where('id', $id)->first();
if ($request->has('image')) {
if (file_exists($small->image)) {
unlink($small->image);
}
DB::table('small_banner')->where('id', $id)->update([
'image' => $request['image']
]);
}
DB::table('small_banner')->where('id', $id)->update([
'title' => $request['title'],
'url' => $request['url'],
'image_title' => $request['image_title'],
'image_alt' => $request['image_alt']
]);
return redirect(route('admin.banners.small.index'));
}
public function small_delete($id)
{
$small = DB::table('small_banner')->where('id', $id)->first();
DB::table('small_banner')->where('id', $id)->delete();
if (file_exists($small->image)) {
unlink($small->image);
}
return redirect(route('admin.banners.small.index'));
}
}
Other Controllers are like SmallController
And this is how I show this banners :
#foreach($smallBanners as $small)
<div class="col-6 col-lg-3">
<div class="widget-banner card">
<a href="{{ $small->url }}" target="_blank" rel="noopener">
<img class="img-fluid w-100" loading="lazy"
src="{{ $small->image }}" title="{{ $small->title }}"
alt="{{ $small->image_alt }}" width="350" height="200">
</a>
</div>
</div>
#endforeach
Other views like small banner.
But in this case, for example in small banners, if we upload 5 images instead 4 images, the structure will be messed up.
What is the best way to manage this banners and optimize codes ?
let's back to the concept, starting from reducing table usage, or you can stay with your concept
lets's change the structure into below
table : banners
columns :
$table->increments('id');
$table->string('title');
$table->string('image');
$table->string('url');
$table->string('image_title')->nullable(); //guessing from validator that it can be null
$table->string('image_alt')->nullable();
//extra columns
$table->enums('banner_type', ['small', 'medium', 'large', 'news']);
//or
$table->string('banner_type');
$table->boolean('isActive')->default(0);
you have model, but not using it
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Banner extends Model
{
protected $table = 'banners'; //add this line to define table name, make sure you have set the database config in .env
protected $fillable = [
'title', 'image', 'url', 'image_title', 'image_alt', 'banner_type', 'isActive'
];
}
now reducing the controller used to manage banners into just 1 Controller
use Banner;
class BannerController extends Controller
{
public function index()
{
$banners = Banner::get();
return view('admin.banners.index', compact('banners'));
}
public function create()
{
return view('admin.banners.create');
}
public function store_count($request, $type)
{
//using array limit
return Banner::where('banner_type', $type)
->where('isActive', 1)->count() < $this->limits[$type] && $request->isActive == 1;
}
public function update_count($banner, $type)
{
return Banner::whereNotIn('id', [$banner->id])
->where('isActive', 1)
->where('type', $banner->banner_type)->count() < $this->limits[$type] && $banner->isActive == 1;
}
public function store(Request $request)
{
//validating form data
$data = $request->validate([
'title' => "required",
'url' => "required",
'image' => "required",
'image_title' => "max:255",
'image_alt' => "max:255",
'banner_type' => "required|in:small,medium,large,news",
'isActive' => "nullable|in:0,1" //active or not
]);
//validating images active count
if (!$this->store_count($request, $request->banner_type)) {
return redirect()->back()->withInput($request->all())
->withErrors(['isActive' => ' نمیتوان بیشتر از ' . $this->limits[$request['banner_type']] . ' عکس برای این بنر آپلود کرد! ']);
}
Banner::create($data);
return redirect(route('admin.banners.index'));
}
public function show($id)
{
$banner = Banner::findOrFail($id);
return view('admin.banners.edit', compact('banner'));
}
public function update(Request $request, $id)
{
$banner = Banner::findOrFail($id);
//validate update form data here
//your validation
//validating images active count
if(!$this->update_count($banner, $request->banner_type)){
return redirect()->back()
->withInput($request->all())
->withErrors(['isActive' => 'There cant be more than '.$this->limits[$request['banner_type']].' images active');
}
$banner = $banner->fill([
'title' => $request['title'],
'url' => $request['url'],
'image_title' => $request['image_title'],
'image_alt' => $request['image_alt'],
'banner_type' => $request['banner_type'],
'isActive' => $request['isActive'] ?? 0
]);
if ($request->has('image')) {
if (file_exists($banner->image)) {
unlink($banner->image);
}
$banner->image = $request['image'];
}
$banner->update();
return redirect(route('admin.banners.index'));
}
public function delete($id)
{
$banner = Banner::findOrFail($id);
if (file_exists($banner->image)) {
unlink($banner->image);
}
$banner->delete();
return redirect(route('admin.banners.index'));
}
}
now we setup code to choose which images are active, you can use ajax method or use controller above
public function set_active($id)
{
$banner = Banner::findOrFail($id);
$this->validate_count((new Request([])), $banner->banner_type);
$banner->update(['isActive' => 1]);
return redirect(route('admin.banners.index'));
}
//you can use array if want to set different limit of banner type, put it as public variable inside controller class
public $limits = [
'small' => 4,
'medium' => 4,
'large' => 4,
'news' => 4
];
load the data resource into view
public class home()
{
$small = Banner::where('banner_type', 'small')
->where('isActive', 1)->get();
$medium = Banner::where('banner_type', 'medium')
->where('isActive', 1)->get();
$large = Banner::where('banner_type', 'large')
->where('isActive', 1)->get();
$news = Banner::where('banner_type', 'news')
->where('isActive', 1)->get();
return view('home', compact('small', 'medium', 'large', 'news'));
}
I need show My laravel application project name with limited characters. that means as an example consider some project name contains more than 10 letters, then I need only show 10 characters.
My project name create controller is
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|min:3',
'notes' => 'required|min:10',
'color' => 'required',
'group' => 'required',
'status' => 'required'
]);
$project = new Project;
$project->project_name = $request->input('name');
$project->project_status = $request->input('status');
$project->group = $request->input('group');
$project->color = $request->input('color');
$project->project_notes = $request->input('notes');
$project->user_id = Auth::user()->id;
$duplicate = Project::where('project_name',$project->project_name)->first();
if($duplicate)
{
return redirect()->route('projects.index')->with('warning','Title already exists');
}
$project->save();
return redirect()->route('projects.index')->with('info','Your Project has been created successfully');
and project name showing blade file is
<div class="row">
#foreach ($projects as $proj)
<div class="col-md-3" style="border:3px solid {!!$proj->color!!};margin-left:5px;margin-bottom: 5px;">
<h2>{!! $proj->project_name !!}</h2>
then how can I show only 10 charactors in My blade file?
You can create a public function in Project model to do this:
public function getShortName($maxLen = 10)
{
if ($this->project_name === null) {
return '-';
}
if (strlen($this->project_name) <= $maxLen) {
return $this->project_name;
}
return substr($this->project_name, 0, $maxLen);
}
Then you can call it in your Blade file like this:
{{ $proj->getShortName() }}
If you want to set another limit to the maximum length, just pass it as a parameter:
{{ $proj->getShortName(20) }}
I need to pass a value from a form(dropdwon) and append this value to a url.
My Routes are:
Route::get('menues/{city?}', 'PagesController#menue');
Route::post('/', 'PagesController#menue');
I have a simple form:
{!!Form::open(array('action' => 'PagesController#menue', 'method' => 'POST'))!!}
{!! Form::select('city', array('heilbronn' => 'Heilbronn', 'stuttgart' => 'Stuttgart')) !!}
{!!Form::submit('Senden')!!}
{!!Form::close()!!}
And this Controller:
public function menue(Request $request, $city = null) {
$searchinput = $request->input('city');
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}]);
if(!is_null($city) && !is_null(User::where('city', $city)->first())) {
$restaurants->where('city', '=', $city);
}
$restaurants = $restaurants->get();
return view('pages.menues')->withRestaurants($restaurants)
//->withArticles($articles)
->withCity($city)
->withSearchinput($searchinput);
}
I need to append the value ($searchinput) from the previous page to show only entries for a particular city.
You need to change your form method attribute to GET, then in your controller you can do follow:
public function menue(Request $request) {
$city = $request->city;
// bla-bla-bla
if ( ! is_null($city) && && ! is_null(User::where('city', $city)->first()) {
// bla-bla
}
// return
}
It seems my validation isnt quite correct, so Im getting this error message while Im trying to store fees into my database.
I have previosuly checked related questions with but it didnt quite help. I created FeeValidator that extends Validator with this array:
<?php namespace \Events\Services\Validations;
use \Events\Services\Validations\AbstractValidator as Validator;
class FeeValidator extends Validator {
protected $rules = array(
'title' => 'required',
'price' => 'required|numeric',
'quantity' => 'integer',
'valid_from' => 'date',
'valid_to' => 'date',
'ticket_limit' => 'integer',
'url_redirect' => 'string',
);
}
Then I have a FeesRepository with this store() function in the FeesRepository class:
<?php namespace \Events\Repositories;
use \Events\Models\Fee as Fees;
use \Events\Models\Event as Event;
use \Events\Repositories\Contracts\FeesRepositoryInterface;
use \Events\Services\Validations\FeeValidator;
class FeeRepository implements FeesRepositoryInterface {
protected $theme;
protected $feeValidator;
public function store($eventId) {
$validation = $this->feeValidator->with(\Input::all());
if ($validation->passes()) {
$fee = new Fees;
$fee->event_id = $eventId;
$fee->title = \Input::get('title');
$fee->price = \Input::get('price');
$fee->quantity = \Input::get('quantity') == "" ? 1 : \Input::get('quantity');
$fee->discount = \Input::get('discount');
$fee->valid_from = \Input::get('valid_from');
$fee->valid_to = \Input::get('valid_to');
$fee->coupon = \Input::get('coupon') == "" ? null : \Input::get('coupon');
$fee->tickets_limit = \Input::get('ticket_limit');
$fee->url_redirect = \Input::get('url_redirect');
$fee->save();
$id = $fee->event->id;
if ( $fee->event->eventable_type == '\Events\Models\Training' )
{
return \Redirect::route('admin.training.edit' , array($id));
}
elseif( $fee->event->eventable_type == '\Events\Models\Meetup' ) {
return \Redirect::route('admin.meetup.edit' , array($id));
}
else
{
return \Redirect::route('admin.conference.edit' , array($id));
}
}
else {
return \Redirect::back()->withInput()->withErrors($this->feeValidator->errors());
}
}
}
Finally you can check my store() function in the FeesController:
<?php namespace \Events\Controllers;
use \Events\Repositories\FeeRepository as Fee;
use \Events\Models\Fee as Fees;use \Events\Services\Validations\FeeValidator;
class FeesController extends \BaseController {
protected $fee;
protected $feeValidator;
public function __construct(Fee $fee , FeeValidator $feeValidator)
{
$this->fee = $fee;
$this->feeValidator = $feeValidator;
}
public function store($eventId) {
return $this->fee->store($eventId);
}
}
Im wondering what is the issue. Can someone give me a hint! Thanks!
For your validation you can use default validation which already build in Laravel https://laravel.com/docs/5.2/validation to display errors you can use JS or simply in your form ex :
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">
#if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>#endif
</div>
</div>
EDIT : hey you have simple validation so you have a easy way to use validation like this but your way is correct but why can't you try easy way ?
This for Laravel 4.2 easy way to use validation example
Route::post('register', function()
{
$rules = array(...);
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails())
{
return Redirect::to('register')->withErrors($validator);
}
});
I am trying to pre-populate some fields in a form and I'm new to relationships.
My controller:
public function index($supplierId) {
$Supplier = new Supplier;
$supplierData = Supplier::find($supplierId);
$supplierData->countryId = ($supplierData->countryId == 0 ? 258 : $supplierData->countryId);
$supplierData->writtenLanguageId = ($supplierData->writtenLanguageId == 0 ? 1 : $supplierData->writtenLanguageId);
$supplierData->paymentTermsId = ($supplierData->paymentTermsId == 0 ? 5 : $supplierData->paymentTermsId);
$countries = Countries::lists('country', 'id');
$languages = Languages::lists('language', 'id');
$paymentTerms = PaymentTerms::lists('term', 'id');
$leadTimes = Leadtimes::lists('leadtime', 'id');
return View::make('supplier.supplier', array(
'supplierData' => $supplierData,
'countries' => $countries,
'languages' => $languages,
'paymentsTerms' => $paymentTerms,
'leadtimes' => $leadTimes
));
}
My model:
class Supplier extends Eloquent {
protected $table = 'suppliers';
public function email() {
return $this->hasOne('SupplierEmail', 'supplierId');
}
public function creditLimits() {
return $this->hasOne('SupplierCreditLimits', 'supplierId');
}
public function website() {
return $this->hasOne('SupplierWebsite', 'supplierId');
}
}
The problem:
<div class='col-xs-12 col-md-6'>{{Form::text('website', $supplierData->website->website, array('class' => 'form-control input-sm'))}}</div>
When there is no row (there is no record), I get:
Trying to get property of non-object (View: C:\wamp\vhosts\view\laravel\app\views\supplier\supplier.blade.php)
How do I get this to work properly?
In your view, use isset to check the value first:
<div class='col-xs-12 col-md-6'>
{{Form::text('website',
isset($supplierData->website->website) ? $supplierData->website->website : '',
array('class' => 'form-control input-sm'))
}}
</div>
Or, better yet, handle this logic in your controller and pass the result to the view:
$supplierData->URL = isset($supplierData->website->website) ? $supplierData->website->website : '';