In my Laravel application, the data are loaded via ajax for a data table. The performance is very bad. So I created a test script to measure the loading time.
public function index()
{
$mt1 = microtime(true);
$data = $this->repo->all();
$resource = ProjectResource::collection($data);
$response = response()->json($resource);
$mt2 = microtime(true);
dd($mt2 - $mt1);
}
There are 200 rows in the DB.
The model has 4 relations.
The script above takes> 6s to render the data.
If I uncomment the line $response = response()->json($resource);, the loading time is < 0.2s
What are the possibilities to speed up the render time for the JSON response?
The $data model:
Appends:
trait ProjectAttribute
{
public function getActionAttribute()
{
return $this->editButton().$this->deleteButton();
}
public function editButton()
{
if (Auth()->user()->can('update salesOrder')) {
return '<button data-toggle="tooltip" data-placement="top" title="'.__('buttons.general.crud.edit').'" class="btn btn-info btn-sm editProject mr-1" ><i class="fas fa-pen"></i></button>';
}
return "";
}
public function deleteButton()
{
if (Auth()->user()->can('delete salesOrder')) {
return '<button data-toggle="tooltip" data-placement="top" title="'.__('buttons.general.crud.delete').'" class="btn btn-danger btn-sm deleteProject" ><i class="fas fa-times"></i></button>';
}
return "";
}
public function getActiveLabelAttribute()
{
if ($this->active) {
return "<span class='badge badge-info'>Aktiv</span>";
}
return "<span class='badge badge-secondary'>Inaktiv</span>";
}
}
The model:
<?php
namespace App\Models\Project\Project;
use Altek\Accountant\Contracts\Recordable;
use Altek\Accountant\Recordable as RecordableTrait;
use App\Models\Traits\Uuid;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Project extends Model implements Recordable
{
use ProjectAttribute, ProjectMethod, ProjectRelationship, ProjectScope, Uuid, RecordableTrait, SoftDeletes;
protected $fillable = [
'name',
'description',
'sales_order_id',
'project_leader_id',
'project_type_id',
'project_status_id'
];
protected $appends = [
'action',
'activeLabel',
'salesOrderName',
'projectLeaderName',
'creatorName',
'statusName',
'statusLabel',
'typeLabel'
];
protected $with = ['projectLeader', 'salesOrder', 'projectType', 'projectStatus'];
}
The resource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Project extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'sales_order_name' => $this->salesOrder->name,
'sales_order' => $this->salesOrder,
'project_leader' => $this->projectLeader,
'project_leader_name'=> $this->projectLeader->full_name,
'creator' => $this->creator,
'creator_name' => $this->creator->full_name,
'type' => $this->projectType,
'type_name' => $this->projectType->name,
'type_label' => $this->projectType->typeLabel,
'status' => $this->projectStatus,
'status_name' => $this->projectStatus->name,
'status_label' => $this->projectStatus->statusLabel,
'created_at' => $this->created_at->format('Y-m-d'),
'action' => $this->action
];
}
}
There are several ways to profile a request to get some information as to what is taking the server so long to respond.
BlackFire - Which comes by default in Laravel Homestead in development or Laravel Forge for production
Laravel DebugBar - Can also be used in development (my personal favorite)
These will give you a lot more information regarding the parts of your code that may be taking time to complete and there are several more if you google around for Laravel or PHP profilers to find something that suits your needs.
Check out Enlightn, a tool to boost your Laravel app's performance and security. It scans your code and server configurations to provide actionable recommendations on improving performance and security.
Related
I've an update form that contains an image and other data to be updated I changed the default route key to use the name instead of the default key which is the ID and I made a separate form request to validate my requests It works fine when posting new record unfortunately it keeps failing with the name field which is unique field; I've checked all threads on github and in stackoverflow with no use although I have the same project in laravel 5.5 and it works fine and now I'm stuck with laravel 6
hereis my form
let data = new FormData();
data.append('name', this.channel.name);
data.append('base_color', this.channel.baseColor);
data.append('complementary_color', this.channel.complementaryColor);
if (this.file){
data.append('avatar', this.file);
}
data.append('_method', 'PUT');
axios.post(`/dashboard/channels/${this.channel.name}`, data).then(resp => {
this.$parent.$emit('channel_updated', resp.data);
}).catch(error => {
flash(error.response.data, 'danger', 'backEndStyle');
});
and here is my route
Route::resource('/dashboard/channels', 'ChannelController');
and here is my form request
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ChannelRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|unique:channels,name,'. $this->id,
'base_color' => 'required',
'complementary_color' => 'required',
];
}
}
here is my controller for update method
public function update(Channel $channel, ChannelRequest $request)
{
$channel->update([
'name' => $request->name,
'bg_base_color' => $request->base_color,
'bg_complementary_color' => $request->complementary_color,
]);
return response($channel->fresh(), 200);
}
Use the ignore constraint to ignore the current model when validating unique
public function rules()
{
return [
'name' => ['required', Rule::unique('channels')->ignore($this->route('channel'))],
'base_color' => 'required',
'complementary_color' => 'required',
];
}
I have a Post Model with these fields :
post_id
post_title
post_content
post_content_full
author
Now I want to use laravel sedders and model factories to create fake fa_IR localized data and insert to posts table.
For that I wrote this in database/factories/ModelFactory.php:
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'post_title' => $faker->sentence,
'post_content' => $faker->paragraph,
'post_content_full' => $faker->paragraph(3),
'author' => $faker->name
];
});
Then I created a PostsTableSeeder class like this :
use Illuminate\Database\Seeder;
class PostsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run ()
{
factory(App\Post::class, 5)->create();
}
}
And in AppServiceProvider.php added below codes to register function :
$this->app->singleton(FakerGenerator::class, function () {
return FakerFactory::create('fa_IR');
});
But After running the seed , laravel uses default locale (en_US) and ignores fa_IR.
I do not know what else to do.
Update:
Even I changed in DEFAULT_LOCALE const vendor/fzaninotto/faker/src/Faker/Factory.php to fa_IR Nothing changed.
Not all faker methods are supported in every language, from what a quick lookup of the documentation says, the Company and Address provider are supported in the fa_IR localization
Try this way
$factory->define(App\Post::class, function () {
$faker = Faker\Factory::create('fa_IR');
return [
'post_title' => $faker->sentence,
'post_content' => $faker->paragraph,
'post_content_full' => $faker->paragraph(3),
'author' => $faker->name
];
});
You need to change the faker locale in your app config file.
First run this
php artisan make:factory PostFactory
Do like this
$faker = \Faker\Factory::create();
Then use like this
$sub_g->name = $faker->name();
$sub_g->country = $faker->country();
$sub_g->state = $faker->state;
Thank me later.
I am trying to add a video section in my website using twig, slim, and eloquent. Now here is what I have for my route for my 'watch' pages
<?php
$app->get('/watch/:series/:episode', function($series, $episode) use($app){
$video = $app->video->where('series', $series)->where('episode', $episode)->first();
$app->render('videos/watch.php', [
'video' => $video
]);
})->name('videos.watch');
now what I want to do is also have it to where when if they do not specifiy an episode number (i.e. type in 'watch/seriesName/') it defaults to the lowest episode number. My database structure is 'id', 'title', 'series', 'episode' (all that really matter to this issue).
In the midst of asking this question I actually figured it out. I will answer my own question so that others who may have the same problem may know what I did.
Here is my video class just in case anyone is interested in how to utilize my video class (not sure if it was the best way of going about handling videos but it works)
<?php
namespace BiosystemStudios\Video;
use Illuminate\Database\Eloquent\Model as Eloquent;
use JBBCode\Parser;
use JBBCode\DefaultCodeDefinitionSet;
class Video extends Eloquent
{
protected $table = 'content_video';
protected $fillable = [
'title',
'series',
'episode',
'location',
'description',
'category',
'is_youtube',
'youtube_link',
'views'
];
public function getTitle()
{
return $this->title;
}
public function getDescription()
{
$parser = new Parser();
$parser->addCodeDefinitionSet(new DefaultCodeDefinitionSet());
$text = $this->description;
$parser->parse($text);
return $parser->getAsHtml();
}
public function getLocation()
{
return $this->location;
}
Rename the first get request to "videos.watch.episode" then create this get request:
$app->get('/watch/:series/', function($series) use($app){
$video = $app->video->where('series', $series)->first();
$app->render('videos/watch.php', [
'video' => $video
]);
})->name('videos.watch');
I am working on my first Zend Framework 2 Project. I needed a User Module and integrated ZfcUser for this. Because I have a slight difference in my User Table, I had to use my own User Entity and User Mapper. I created a new Module called ZfcUserExtension.
I then copied a lot of files from the original ZfcUSer Module like:
Entity/User.php
Entity/UserInterface.php
Factory/Entity/IndexControllerFactory.php
Factory/Mapper/UserHydratorFactory.php
Mapper/Exeption/ExceptionInterface
Mapper/Exeption/InvalidArgumentException.php
Mapper/Exeption/RuntimeException.php Mapper/HydratorInterface.php
Mapper/User.php Mapper/UserHydrator.php Mapper/UserHydrator.php
Mapper/UserInterface.php
In zfcuser.global.php I set the user_entity_class to use my own Entity.
'user_entity_class' => 'ZfcUserExtension\Entity\User',
In the module.config.php from the ZfcUserExtension I add the below to make sure that I use my own User Mapper and UserHydrator. The reason for that was that I use "id" as a Primary Key in my User table instead of "user_id", so I had to make sure that this gets overwritten as well.
<?php
return array(
'controllers' => array(
'factories' => array(
'ZfcUserExtension\Controller\Index' => function(Zend\Mvc \Controller\ControllerManager $cm) {
$sm = $cm->getServiceLocator();
return new \ZfcUserExtension\Controller\IndexController(
$sm->get("doctrine.entitymanager.orm_default")
);
}
),
),
'service_manager' => array(
'factories' => array(
'zfcuser_user_mapper' => function ($sm) {
$options = $sm->get('zfcuser_module_options');
$mapper = new \ZfcUserExtension\Mapper\User();
// No db adapter present add below line
$mapper->setDbAdapter($sm->get('zfcuser_zend_db_adapter'));
$entityClass = $options->getUserEntityClass();
// No entity prototype set add below line
$mapper->setEntityPrototype(new $entityClass);
$mapper->setHydrator($sm->get('zfcuser_user_hydrator'));
$mapper->setTableName($options->getTableName());
return $mapper;
},
// 'zfcuserextension_change_password_form' => 'ZfcUserExtension\Factory\Form\ChangePhoneFormFactory',
),
),
I finally got all this to work, till I now run into another problem. I want some additional fields for the User like Phone Number. How would I approach this? I know there are some ideas on the Internet, but I am mainly interested to know how I would actually offer the option to have a "Change Phone" Form. I have created a Form, similar to the "Change Password and "Change Email". I have then created a IndexController.php in my ZfcUSerExtension, again followed the set-up of the UserController from the ZfcUser Module
class IndexController extends AbstractActionController {
const ROUTE_LOGIN = 'zfcuser/login';
/**
* #var \Doctrine\ORM\EntityManager
*/
protected $em;
public function __construct(\Doctrine\ORM\EntityManager $em)
{
$this->em = $em;
}
/**
* #var Form
*/
protected $changeEmailForm;
public function indexAction() {
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute(static::ROUTE_LOGIN);
}
return new ViewModel();
}
public function changephoneAction() {
// if the user isn't logged in, we can't change phone
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute(static::ROUTE_LOGIN);
}
$form = $this->getChangePhoneForm();
$request = $this->getRequest();
$request->getPost()->set('PrevPhone', $this->getUserService()->getAuthService()->getIdentity()->getPrevPhone());
return array(
'status' => false,
'changePhoneForm' => $form,
);
$fm = $this->flashMessenger()->setNamespace('change-phone')->getMessages();
if (isset($fm[0])) {
$status = $fm[0];
} else {
$status = null;
}
$prg = $this->prg(static::ROUTE_LOGIN);
if ($prg instanceof Response) {
return $prg;
} elseif ($prg === false) {
return array(
'status' => $status,
'changePhoneForm' => $form,
);
}
$form->setData($prg);
if (!$form->isValid()) {
return array(
'status' => false,
'changePhoneForm' => $form,
);
}
$change = $this->getUserService()->changeEmail($prg);
if (!$change) {
$this->flashMessenger()->setNamespace('change-email')->addMessage(false);
return array(
'status' => false,
'changeEmailForm' => $form,
);
}
$this->flashMessenger()->setNamespace('change-email')->addMessage(true);
return $this->redirect()->toRoute(static::ROUTE_CHANGEEMAIL);
}
public function getChangePhoneForm()
{
$sl = $this->getServiceLocator();
$this->setChangePhoneForm($sl->get('zfcuserextension_change_phone_form'));
return $this->changePhoneForm;
}
public function setChangePhoneForm($changePhoneForm)
{
$this->changePhoneForm = $changePhoneForm;
return $this;
}
I now noticed that I will face a problem with the User Service Service/User.php. The Service offers a changePassword() and changeEmail() Method. I now thought that I need to copy this file into my own Modules. Am I right that if I extend the User Service from ZfcUser then the Methods changePassword() and changeEmail() will still be available, so I would delete it from the just copied file and just add changePhone()?
And if I am right with my thoughts, the User Service currently starts like this:
class User extends EventProvider implements ServiceManagerAwareInterface
How would I have to change it that I extend the original User Service? I hope somebody can help, I am still rather confused with all this. Thanky you very much in advance.
There are two possible methods:
Build custom classes extending ZfcUser's entity, form and input filter and add your custom fields. In the ZfcUser configuration change aliases or override factories to ensure your custom classes are instantiated rather than the built in ones.
If you are OK with having the custom profile fields stored and accessed separately from the ZfcUser user entity, check out my module on GitHub: LdcUserProfile. It provides a profile system for ZfcUser but also makes it easy to add your own custom profile fieldsets linked to a user.
This is a wierd situation because magento is loading my backend model, its just not calling it when I load and save it. I know this because 1. I see it in my database, 2. when I rename my backend model, my test case fails. Here is my code
It saves my values just fine and completely ignores my afterload and beforesave methods.
TEST CASE
<?php
class Super_Base_Test_Controller_Test extends EcomDev_PHPUnit_Test_Case_Controller {
const DEFAULTSTORE = 1;
public function setUpMocks() {
$this->setCurrentStore(1);
$customer = Mage::getSingleton('customer/customer')
->load(1);
$customer->setCoinBalance(20)
->save();
}
public function setUp() {
$this->setUpMocks();
$data = array(
'customer_id'=>1,
'message'=>'this is a test message',
'income'=>20,
'created_at'=>'9/11/84',
'updated_at'=>'9/11/84',
'current'=>1
);
$this->getRequest()->setParams($data);
}
protected function getTearDownOperation() {
return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
}
backend model
<?php
/**
* Created by PhpStorm.
* User: numerical25
* Date: 3/8/14
* Time: 6:22 PM
*/
class Super_Coin_Model_Customer_Attribute_Coinbalance extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract {
protected function _afterLoad()
{
if (!is_array($this->getValue())) {
$value = $this->getValue();
$this->setValue(empty($value) ? false : unserialize($value));
}
}
protected function _beforeSave() {
if (is_array($this->getValue())) {
$this->setValue(serialize($this->getValue()));
}
}
public function setCoinAmount($amount) {
$this->setValue($amount);
}
}
installation file
$eavsetup->addAttribute('customer', 'coin_balance', array(
'input' => 'text',
'type' => 'decimal',
'label' => 'Customer Coin Balance',
'backend' => 'coin/customer_attribute_coinbalance',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 1, ));
When I set break points, the system completly ignores my methods.
Look at abstract class Mage_Eav_Model_Entity_Attribute_Backend_Abstract. It contains the following public methods: beforeSave() and afterLoad().
There are no _afterLoad() and _beforeSave() methods in that class