Why does Laravel dd only show two levels? - laravel

When I use dd($myVar) in Laravel the output only shows two levels. Why is that?
The first level is shown expanded, and I can click to expand the second level. The third level is simply summarised with something like array:2 (in the case of any array with two elements).
EDIT:
I noticed that the output of var_dump() was similarly limited. I changed the xdebug depth setting to 10, ini_set('xdebug.var_display_max_depth', 10), which fixed the problem in var_dump, but not dd.

The easiest way is to use ctrl+click to expand all children, you can even search values and variables using ctrl+F
If it doesn't suit you, you can create your own helper that depends on xdebug configuration settings. Add a new file "helpers.php" then autoload it using composer.json
"autoload": {
"files": [
"app/helpers.php"
]
}
I used an anonymous class, you may create a dedicated class to cleanup/reuse code
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Illuminate\Support\Debug\HtmlDumper;
function xdebug_dd(...$args)
{
http_response_code(500);
$obj = new class {
public function dump($value)
{
if (class_exists(CliDumper::class)) {
$dumper = new HtmlDumper;
$dumper->dump((new VarCloner)->cloneVar($value), null, [
'maxDepth' => ini_get('xdebug.var_display_max_depth')
]);
} else {
var_dump($value);
}
}
};
foreach ($args as $x) {
$obj->dump($x);
}
die(1);
}

Related

PhpStorm No Usages for get Attribute

I'm using the latest version of PhpStorm (2022.3.1) and Laravel 9+. This is not a huge issue, but rather a major eyesore.
For some reason when I use a Model to create a custom Attribute like this:
public function getFormattedStartDateAttribute(): string
{
if (!$this->start_date) {
return 'TBD';
} else {
return $this->start_date->format('M. d, Y');
}
}
And use in the view like this or this:
Date {{ $event->formattedStartDate }}
Date {{ $event->formatted_start_date }}
PhpStorm still says the method has no usages?
Image:
Is there a way to fix this? I've tried reindexing my project. This is a new feature called Code Vision.
The issue is very easy to solve, you can use barryvdh/laravel-ide-helper and then run php artisan ide:model, that will go over the models and create a PHPDoc block (you can add options and create them in the same model file or in a new file where you only have this PHPDock blocks), and PHPStorm will read this doc block and know when you are calling attributeWhatever is what type.
It will add this in your case:
/**
* #property string $formattedStartDate
*/
This way, any IDE that is capable of understanding PHPDock blocks, will understand that when you do $class->formattedStartDate, you are refering to that one, and it is of type string.
BUT, no IDE (unless using a plugin that I am not aware of) will understand that getFormattedStartDateAttribute -> formattedStartDate, so you will still get no usages for getFormattedStartDateAttribute, but at least you can track formattedStartDate and do whatever you want with it.
One quick tip, if you are using Laravel 9+, please change that code from:
public function getFormattedStartDateAttribute(): string
{
if (!$this->start_date) {
return 'TBD';
} else {
return $this->start_date->format('M. d, Y');
}
}
To:
public function formattedStartDate(): \Illuminate\Database\Eloquent\Casts\Attribute
{
return Attribute::get(
function ($value, $attributes) {
if (! $attributes['start_date']) {
return 'TBD';
} else {
return $attributes['start_date']->format('M. d, Y');
}
}
);
}
Why? Because using getFormattedStartDateAttribute is the old way, Laravel 9+ made it easier, read about Accessors.
See that getXXXXAttribute and setXXXXAttribute is not even present on the documentation anymore.

Setting up Laravel-excel and PhpSpreadsheet macro

I am using Maatwebsite Laravel-excel version 3.1. And I want to set the default styling of the sheet. I have read the documentation about including a macro in your laravel app by setting this in my AppServiceProvider boot() method. :
Sheet::macro('getDefaultStyle',function(Sheet $sheet){
$sheet->getDefaultStyle();
});
But when everytime i reload the page it crashes the page and the laravel server in my cmd stops and re run. Here is my Export.php looks like:
public function registerEvents():array
{
return[
AfterSheet::class=>function(AfterSheet $event){
$header_style_array = [
'font'=>['bold'=>true]
];
$style_array = [
'font'=>['bold'=>true]
];
$event->sheet->getStyle('A1:B1')->getAlignment()->setHorizontal('center');
$event->sheet->getStyle('A1:B1')->applyFromArray($header_style_array);
$event->sheet->getDefaultStyle()->getFont()->setSize(5);
}];
}
I already included use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Events\AfterSheet; above my Export.php file.
Is there something that I missed? I find this so hard to set up. And there's little article about setting this up.
Any help would be much appreciated
Refs: https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#styles
https://docs.laravel-excel.com/3.1/exports/extending.html
If you examine the documentation for PhpSpreadsheet, I think you will find that the getDefaultStyle() method is not accessible from the active sheet.
To Laravel Excel, $event->sheet is equivalent to $spreadsheet->getActiveSheet(). This is why your current configuration will not work.
// this doesn't work
// $spreadsheet->getActiveSheet()->getDefaultStyle()->getFont()->setSize(5);
// this does
$spreadsheet->getDefaultStyle()->getFont()->setSize(5);
You should set default styles through the writer in BeforeWriting.
public function registerEvents():array
{
return [
BeforeWriting::class=>function(BeforeWriting $event){
$event->writer->getDefaultStyle()->getFont()->setSize(5);
},
];
}
If you want to turn this into a macro, you should use a Writer macro rather than a Sheet macro.
https://docs.laravel-excel.com/3.1/exports/extending.html#writer
public function registerEvents():array
{
Writer::macro('setDefaultStyle', function (Writer $writer) {
$writer->getDefaultStyle()->getFont()->setSize(5);
});
return [
BeforeWriting::class=>function(BeforeWriting $event){
$event->writer->setDefaultStyle();
},
];
}

Silverstripe 4 - SiteConfig module Image not working in template

I can't seem to get Silverstripe 4 to display images included in SiteConfig in my templates at all.I used to be able to just doe something like $SiteConfig.Logo and it would print out a automatic tag.
CustomSiteConfig:
<?php
use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\HeaderField;
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\Image;
use SilverStripe\ORM\DataObject;
use SilverStripe\CMS\Model\SiteTree;
class CustomSiteConfig extends DataExtension
{
private static $db = [
];
private static $has_one = [
'Logo' => Image::class,
'MobileLogo' => Image::class
];
private static $owns = [
'Logo',
"MobileLogo"
];
public function updateCMSFields(FieldList $fields)
{
$uploader = UploadField::create('Logo');
$uploader->setFolderName('Logo');
$uploader->getValidator()->setAllowedExtensions(['png','gif','jpeg','jpg']);
$fields->addFieldsToTab('Root.Main', [
HeaderField::create('hf2','Default logo'),
$uploader
]);
$uploader2 = UploadField::create('MobileLogo');
$uploader2->setFolderName('MobileLogo');
$uploader2->getValidator()->setAllowedExtensions(['png','gif','jpeg','jpg']);
$fields->addFieldsToTab('Root.Main', [
HeaderField::create('hf3','Mobile Logo'),
$uploader2
]);
}
}
But when I try in my template file. I get no URL
$SiteConfig.Logo
or
$SiteConfig.Logo().Link
etc
Nothing works?
A few things to check:
Verify that $SiteConfig is available as variable at that point in your template (Try using $SiteConfig.Title)
Verify that the extension is actually added to SiteConfig (do you see the CMS Fields?)
Did you add $owns later? run ?flush=1 again and re-save the SiteConfig *
Verify that both the SiteConfig and the File is published. (Save & Publish the SiteConfig twice, then check in the file manager if the file is published) **
[*] $owns is just a directive that when SiteConfig->doPublish() is called, it will also publish all files
[**] I've seen a bug that DataObjects don't actually publish files sometimes. Saving twice might work.
Just like Zauberfisch said, your image is probably not published. However, publishing the image after writing the owner can be tricky.
I usually through in this code
public function onAfterWrite()
{
parent::onAfterWrite();
if ( $this->LogoID ) {
$this->Logo()->doPublish();
}
if ( $this->MobileLogoID ) {
$this-> MobileLogo()->doPublish();
}
}
It's messy, I know, but it can save you a couple of hours. After saving you can remove it as the $owns hook will start to kick-in to all newly created objects.
We can Use This one
$SiteConfig.Logo.URL

TYPO3: clear cache of a page when file metadata is changed

I have a custom plugin which shows files for download based on sys_category.
When an editor changes the meta data of a file, e.g. changes the title or category, the changes are only reflected in the frontend when the complete frontend cache is cleared.
I've tried to add this to page TSconfig:
[page|uid = 0]
TCEMAIN.clearCacheCmd = 17
[global]
But this doesn't work. Any other idea how to clear the cache, when a sys_file_metadata record is changed?
Here is my solution. Thx Aristeidis for the hint.
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['my_extension_key'] =
\Vendor\ExtKey\Hooks\DataHandler::class;
Classes/Hooks/DataHandler.php
<?php
namespace Vendor\ExtKey\Hooks;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class DataHandler
{
public function processDatamap_afterDatabaseOperations(
$status,
$table,
$recordUid,
array $fields,
\TYPO3\CMS\Core\DataHandling\DataHandler $parentObject
) {
if ($table === 'sys_file_metadata') {
// hardcoded list of page uids to clear
$pageIdsToClear = [17];
if (!is_array($pageIdsToClear)) {
$pageIdsToClear = [(int)$pageIdsToClear];
}
$tags = array_map(function ($item) {
return 'pageId_' . $item;
}, $pageIdsToClear);
GeneralUtility::makeInstance(CacheManager::class)->flushCachesInGroupByTags('pages', $tags);
}
}
}
Of course this could be improved more:
Currently the list of page uids is hardcoded. That could be made configureable via extension manager settings.
A check could be implemented to only delete the cache if the file has a certain sys_category assigned, e.g. Downloads
But for the moment this solution is enough for my needs.

How to extend laravel 4 core?

I am a newb learning laravel 4. I want to override specific helper functions. Or add new functions to Url, Str etc. How to do this?
Depending on what part of Laravel you want to extend or replace, there are different approaches.
Macros
Adding functions to Str is really easy, because of "macros":
Here's a short example for adding function:
Str::macro('test', function($str) {
return 'Testing: ' . $str . '!';
});
You can then call this function as expected:
echo Str::test('text'); // Outputs "Testing: text!"
Adding functions using macros are supported by Str, Form, HTML and Response.
IOC Based Extension
To extend URL one must use the IOC of Laravel. This is explained in the docs (as mentioned by BenjaminRH). I agree it can be a bit hard to understand. Here's a step-by-step to extend URL:
Create folder app/lib to hold your extension classes.
Add this folder to autoloading:
In app/start/global.php, append the lib path to the class loader:
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/lib'
));
Then add the path to composer.json classmap:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/lib"
]
},
Create the custom UrlGenerator app/lib/CustomUrlGenerator.php:
<?php
use \Illuminate\Routing\UrlGenerator;
class CustomUrlGenerator extends UrlGenerator
{
public function test()
{
return $this->to('/test');
}
}
Create a service provider app/lib/CustomRoutingServiceProvider.php:
<?php
use \Illuminate\Routing\RoutingServiceProvider;
class CustomRoutingServiceProvider extends RoutingServiceProvider
{
public function boot()
{
App::bind('url', function()
{
return new CustomUrlGenerator(
App::make('router')->getRoutes(),
App::make('request')
);
});
parent::boot();
}
}
Register the service provider in app/config/app.php:
Add CustomRoutingServiceProvider to the providers array.
For example, right after the Workbench provider:
'Illuminate\Workbench\WorkbenchServiceProvider',
'CustomRoutingServiceProvider',
Run composer dump-autoload from project root folder.
Done. Use like:
URL::test();
NOTE The code is tested, but may contain some errors
Interesting that you should mention this, actually. A whole documentation section was just recently added, which covers this in detail. It's very clear, and easy to understand. If you've been using Laravel at all, it might not even surprise you that Laravel actually provides an extend method for a lot of core components.
Following Fnatte's answer, today's versions of Laravel do some extra processing in the url binding. Redefining the whole binding is no longer a practical option.
Here is how I ended up for extending the URL facade.
First, create your child class using this boilerplate:
use Illuminate\Routing\UrlGenerator;
class YourUrlGenerator extends UrlGenerator {
public function __construct(UrlGenerator $url)
{
parent::__construct($url->routes, $url->request);
}
// redefine or add new methods here
}
Then, add this in a ServiceProvider:
$url = $this->app['url'];
$this->app->singleton('url', function() use ($url)
{
return new YourUrlGenerator($url);
});
The point is simply that the original url binding should be executed at least once before we override it with our own.

Resources