I am writing a simple custom directive in Laravel. Whenever I make some changes in the code of custom directive, its not reflected in the view until I
Comment the directive in view.
Reload the page
Uncomment the directive
Reload the page to finally get the changes
Custom directive code in global.php
Blade::extend(function($value, $compiler)
{
$pattern = $compiler->createMatcher('molvi');
return preg_replace($pattern, '$1<?php echo ucwords($2); ?>', $value);
});
Directive call in view
#molvi('haji') //this will output 'Haji' due to ucwords($2)
//the ucwords() is replaced with strtolower()
#molvi('haji') //this will still output 'Haji'
I am converting the words to uppercase. When lets say I want to use strtolower() instead of ucwords(), I have to repeat above steps to get changes reflected.
UPDATE
I have tried to clear the cache with various methods as described in this thread but still no success.
UPDATE
Since no one is answering this question on StackOverFlow, I have posted it on laravel github.
Note: I am just pasting the answer given by #lukasgeiter on github thread.
The problem is that the compiled views are cached and you can't
disable that. You can however clear the files. Either manually by
deleting everything in storage/framework/views or by running the
command php artisan view:clear
Not supported in Laravel 4 or 5.0
This command is not found in Laravel 4 or 5.0. Its a new command and introduced in Larvel 5.1. Here is the ViewClearCommand code from 5.1.
Manually add support in Laravel 4 or 5.0
You can manually add support in Laravel 4 or 5.0.
Register new command
The way to achieve it in previous versions is to register new command. The Aritsan Development section is helpful in this regard.
Final working code for 4.2.1
I have tested the following code on 4.2.1.
Add new command file
app/commands/ClearViewCommmand.php
<?php
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class ClearViewCommand extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'view:clear';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Clear all compiled view files';
protected $files;
/**
* Create a new command instance.
*
* #return void
*/
public function __construct(Filesystem $files)
{
parent::__construct();
$this->files = $files;
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
//this path may be different for 5.0
$views = $this->files->glob(storage_path().'/views/*');
foreach ($views as $view) {
$this->files->delete($view);
}
$this->info('Compiled views cleared!');
}
}
Register new command
Add the following line in app/start/artisan.php
Artisan::resolve('ClearViewCommand');
CLI
Now finally you can run the command. After each update of code in custom directive you can run this command to get immediate changes in views.
php artisan view:clear
Related
I made a laravel component using command php artisan make:component TestComponent
So, two files(resources/view/component/test-component.blade.php and app/View/Components/TestComponent.php) was created.
However, test-component.blade.php file was worked fine, but TestComponent.php file was ignored.
I check this issue to change render method like that.
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class TestComponent extends Component
{
/**
* Create a new component instance.
*
* #return void
*/
public $id;
public function __construct($id="test")
{
$this->id = $id;
}
/**
* Get the view / contents that represent the component.
*
* #return \Illuminate\Contracts\View\View|string
*/
public function render()
{
return view('components.foofoofoofoofoo'); // fake view name
}
}
The fake view name(foofoofoofoofoo) was ignored and test-component view was rendered.
And id variable doesn't delivered to view when I use default value like <x-test-component />
(<x-test-component id='abc' /> was worked fine.)
I try to register manually in boot method on AppServiceProvider.php
public function boot()
{
Blade::component('test-component', App\View\Components\TestComponent::class);
}
But it doesn't work too.
php artisan clear:view, php artisan cache:clear, composer dump doesn't work on this issue.
I solved this problem to update laravel version to 8.38.0 and run php artisan view:clear
so I have created my own blog package in a structure of Packages/Sitemanager/Blog I have a service provider that looks like the following:
namespace Sitemanager\Blog;
use Illuminate\Support\ServiceProvider as LaravelServiceProvider;
class BlogServiceProvider extends LaravelServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot() {
$this->handleConfigs();
$this->handleMigrations();
$this->handleViews();
$this->handleRoutes();
}
/**
* Register the service provider.
*
* #return void
*/
public function register() {
// Bind any implementations.
$this->app->make('Sitemanager\Blog\Controllers\BlogController');
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides() {
return [];
}
private function handleConfigs() {
$configPath = __DIR__ . '/config/blog.php';
$this->publishes([$configPath => config_path('blog.php')]);
$this->mergeConfigFrom($configPath, 'blog');
}
private function handleTranslations() {
$this->loadTranslationsFrom(__DIR__.'/lang', 'blog');
}
private function handleViews() {
$this->loadViewsFrom(__DIR__.'/views', 'blog');
$this->publishes([__DIR__.'/views' => base_path('resources/views/vendor/blog')]);
}
private function handleMigrations() {
$this->publishes([__DIR__ . '/migrations' => base_path('database/migrations')]);
}
private function handleRoutes() {
include __DIR__.'/routes.php';
}
}
Now, what i would like to do is run the migrations dynamically if they have never been run before or within an installation process i suppose. I've seen in older documentation you could so something like this:
Artisan::call('migrate', array('--path' => 'app/migrations'));
However, this is invalid in laravel 5, how can I approach this?
Artisan::call('migrate', array('--path' => 'app/migrations'));
will work in Laravel 5, but you'll likely need to make a couple tweaks.
First, you need a use Artisan; line at the top of your file (where use Illuminate\Support\ServiceProvider... is), because of Laravel 5's namespacing. (You can alternatively do \Artisan::call - the \ is important).
You likely also need to do this:
Artisan::call('migrate', array('--path' => 'app/migrations', '--force' => true));
The --force is necessary because Laravel will, by default, prompt you for a yes/no in production, as it's a potentially destructive command. Without --force, your code will just sit there spinning its wheels (Laravel's waiting for a response from the CLI, but you're not in the CLI).
I'd encourage you to do this stuff somewhere other than the boot method of a service provider. These can be heavy calls (relying on both filesystem and database calls you don't want to make on every pageview). Consider an explicit installation console command or route instead.
After publishing the package:
php artisan vendor:publish --provider="Packages\Namespace\ServiceProvider"
You can execute the migration using:
php artisan migrate
Laravel automatically keeps track of which migrations have been executed and runs new ones accordingly.
If you want to execute the migration from outside of the CLI, for example in a route, you can do so using the Artisan facade:
Artisan::call('migrate')
You can pass optional parameters such as force and path as an array to the second argument in Artisan::call.
Further reading:
https://laravel.com/docs/5.1/artisan
https://laravel.com/docs/5.2/migrations#running-migrations
For the Laravel 7(and probably 6):
use Illuminate\Support\Facades\Artisan;
Artisan::call('migrate');
will greatly work.
What's the best way ( or maybe the way it's actually done ) of creating an artisan command for generating custom classes or files? Like php artisan make:console itself that creates a php class for our new artisan command.
From what I can think of, we have two options:
Add the template for that new file using php heredoc(or any string inside the new command's class file for that matter), which is really messy.
Put a template file somewhere, read it, replace what's necessary, and then create the new file. But I don't know where would be best to put the template file.
So is there a best-practice for handling this situation in Laravel? I googled it, but there was only articles and documentation for simple artisan command creation.
Update 04/2020: Laravel 7 comes with a way to edit the default stubs to make changes to them and have Laravel pick up those changes. If you want to make a completely different stub to publish a totally different file the process below is appropriate otherwise look at the docs at the link below.
https://laravel.com/docs/7.x/artisan#stub-customization
I know this question is a bit old but this is pretty easy if you just want to create a similar file that Laravel already does. (I wanted to create a job with some custom traits attached on creation)
So first look at the stubs Laravel comes with here on github.
Next, pick the stub of the type of class you want (I copied the job-queued stub) and paste it somewhere you can access in your app. I put mine inside App\Console\Stubs since that makes sense that commands will use the stubs.
After that, create your artisan command with php artisan make:command commandName.
Inside the command created use this file Illuminate\Console\GeneratorCommand. Now make your command extend this class instead of Command; This class is the class Laravel uses to create classes and it extends Command itself.
Inside your command create a few properties and methods as follows:
protected $name = 'make:custom-file'; The name of your command. This replaces $signature
protected $description = 'Command description.';
protected $type = 'Job'; Type of class to make
//location of your custom stub
protected function getStub()
{
return app_path().'/Console/Stubs/custom-job.stub';
}
//The root location the file should be written to
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Jobs';
}
//option flags if any see this for how it works
protected function getOptions()
{
return [];
}
A full example of how the class should look is like this:
<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
class CustomJob extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $name = 'make:custom';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Create a custom job.';
/**
* The type of class being generated.
*
* #var string
*/
protected $type = 'Job';
/**
* Get the stub file for the generator.
*
* #return string
*/
protected function getStub()
{
return app_path().'/Console/Stubs/custom-job.stub';
}
/**
* Get the default namespace for the class.
*
* #param string $rootNamespace
* #return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Jobs';
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return [];
}
}
Once you run your custom artisan command it will write your custom stub to where you specify.
Laravel uses .stub files as templates, and replaces the tokens inside the template.
Since you mentioned the make:console command, for reference you can take a look at the following files:
vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs/console.stub
(on github)
This the template for making new console commands.
vendor/laravel/framework/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php
(on github)
This is the code that is executed when you run the php artisan make:console command.
If you want to take a look at packages that have done this, as well, a good example is the generators package by Jeffrey Way at Laracasts.
Just done a fresh install of L5 and, as per the documentation, i'm trying to share data with all views using a simple share method in the AppServiceProvider class.
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use View;
class AppServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('website', 'test');
}
/**
* Register any application services.
*
* This service provider is a great spot to register your various container
* bindings with the application. As you can see, we are registering our
* "Registrar" implementation here. You can add your own bindings too!
*
* #return void
*/
public function register()
{
$this->app->bind(
'Illuminate\Contracts\Auth\Registrar',
'App\Services\Registrar'
);
}
}
route file:
Route::get('/', function(){
return view('test');
});
blade file:
<h1>Test</h1>
{{ $website }}
This should be really easy, so i'm wondering if i've made a very obvious mistake at the installation stage.
Thanks
Most probably you should clear the compiled.php file by running:
php artisan clear-compiled
or by manual deleting vendor/compiled.php (in previous L5 versions it's storage/framework/compiled.php).
Here's the explanation. Laravel pre-compiles certain classes that are used on basically every request. This serves the purpose of performance optimization. Files to compile can be specified in config/compile.php under files. The default one looks like this:
'files' => [
realpath(__DIR__.'/../app/Providers/AppServiceProvider.php'),
realpath(__DIR__.'/../app/Providers/BusServiceProvider.php'),
realpath(__DIR__.'/../app/Providers/ConfigServiceProvider.php'),
realpath(__DIR__.'/../app/Providers/EventServiceProvider.php'),
realpath(__DIR__.'/../app/Providers/RouteServiceProvider.php'),
],
That means if you change one of those precompiled files, changes won't be applied immediately (if compiled.php exists) but only after you run php artisan optimize again or after you run php artisan clear-compiled to clear the compiled.php file.
I'm trying to develop a package in laravel 4 - my first attempt at a package.
I found a couple of tutorials which I've tried to follow:
http://jasonlewis.me/article/laravel-4-develop-packages-using-the-workbench
and
http://culttt.com/2013/06/24/creating-a-laravel-4-package/
and of course in the official documentation.
I've followed the basic structure to create the framework. However on loading the app I get a class not found error. This relates directly to the serviceprovider I have placed in the app.php file.
here's my entry in the providers array:
'Longestdrive\Calendar\CalendarServiceProvider'
My folder structure is:
laravel/workbench/longestdrive/calendar/src/Longestdrive/Calendar
My service provider has the following entries:
<?php namespace Longestdrive\Calendar;
use Illuminate\Support\ServiceProvider;
class CalendarServiceProvider extends ServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
$this->package('longestdrive/calendar');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array();
}
}
I've double checked to spelling and ran a composer dump-autoload both from the root of the project and the root of the package.
I've run out of ideas for solving the class not found any ideas where I've gone wrong?
The line producing the error is this one:
C:\wamp\www\googleapi\laravel\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRepository.php
Any help appreciated
Thanks
Update:
I ran a composer update as suggested in the workbench/package folder with a response nothing to update. I then ran composer at the root of the project and an error was produced:
[RuntimeException]
Error Output: PHP Fatal error: Class 'Longestdrive\Calendar\CalendarServiceProvider' not found
in C:\wamp\www\googleapi\laravel\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRe
pository.php on line 123
I probably posted the wrong error line earlier. The full exception response is:
Class 'Longestdrive\Calendar\CalendarServiceProvider' not found
THe error extract:
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #return \Illuminate\Support\ServiceProvider
*/
public function createProvider(Application $app, $provider)
{
return new $provider($app);
}
which I assume relates to the service provider loader not finding the CalendarServiceProvider?
I found that running composer install from within the workbench/[vendor]/[package] folder solved the problem.
I encountered the same error, so I went deeper on its flow to knew what happens.
So dissecting a little bit basically, in the bootstrap phase, when bootstrap/autoload.php is loaded it runs at the end:
if (is_dir($workbench = __DIR__.'/../workbench'))
{
Illuminate\Workbench\Starter::start($workbench);
}
This requires EVERY workbench/vendor/package/**/**/**/autoload.php he found (by using Symfony Finder Component)
$finder->in($path)->files()->name('autoload.php')->depth('<= 3');
That's important because it's expecting to find workbench/vendor/package/vendor/autoload.php.
Successively in bootstrap/start.php it gets the 'providers' defined in config/app.php and try to load each of them:
$providers = $config['providers'];
$app->getProviderRepository()->load($app, $providers);
and then in ProviderRepository.php
foreach ($providers as $provider)
{
$instance = $this->createProvider($app, $provider);
so we'll end up with:
public function createProvider(Application $app, $provider)
{
return new $provider($app);
where it tried to create an instance of a class isn't really autoloaded. And so that's why the exception thrown!
In conclusion...
As #Ray said, by removing his Service from 'providers' => array( no error is thrown cause return new $myServiceDeclaredInProviderArray($app); never fires for that service.
As #Andrew Holt said
I found that running composer install from within the workbench/[vendor]/[package] folder solved the problem.
He's absolutely right because this create the autoload vendor dir and files, and everything works as we expect it to because it finds the autoload files:
$finder->in($path)->files()->name('autoload.php')->depth('<= 3');
Me
php artisan dump-autoload works as well if you remove the service from the providers array
In addition to #ilpaijin's and #Andrew Holt's answer, there sometimes comes the need (when there's a new version of Laravel) to run composer update within the workbench/vendor/package folder.
Also, as noted here, the composer.json within the package must require the same version of illuminate/support as the one required of laravel/framework in the project root's composer.json.
Thanks to #biscii note that one should use:
"illuminate/support": "4.1.x"
instead of
"illuminate/support": "4.x"