Posts

Since 2024
SQLite Studio is a SQLite Database Explorer
SQLite Studio is a SQLite Database Explorer

SQLite seems to be cropping up everywhere! Laravel 11 uses SQLite by default when creating a new project, and Rails' default database is SQLite as well. A host of Database GUIs now support SQLite. Production services like Turso help use SQLite in production, and many prominent community developers are promoting SQLite. We covered TablePlus on Laravel News in 2017, and it remains a solid GUI option for managing SQLite databases. Other options include integrated database tools in PHPStorm and other JetBrains products, a full-on database IDE by JetBrains called DataGrip, and many others. SQLite Studio doesn't necessarily compete with the above-mentioned GUI tools; it is a single-file binary, single-command SQLite database explorer. It offers the following features: Overview page with common metadata. Tables page with each table's metadata, including the disk size being used by each table. Infinite scroll rows view. A custom query page that gives you more access to your db. Connect to a local SQLite database, a remote libSQL Server, or PostgreSQL Server My favorite feature is the infinite scroll rows view and the responsive updates as you write SQL queries in the Queries tab: SQLite Studio also gives you a Birds Eye view of the database on the Overview tab, which summarizes the database file size, SQLite version, total number of tables, rows per table, metadata, and more: The technology behind SQLite Studio looks fantastic—it uses Rust for the backend and TypeScript, React, Tailwind CSS, and Vite for the UI. If you want to see a live version of SQLite Studio in action, check out SQLite Studio's sample.db. This CLI is open-source on GitHub at frectonz/sqlite-studio. Related: DevDB - Access your database right inside VS Code! - Laravel News The post SQLite Studio is a SQLite Database Explorer appeared first on Laravel News. Join the Laravel Newsletter to get Laravel articles like this directly in your inbox.

Running a Single Test, Skipping Tests, and Other Tips and Tricks
Running a Single Test, Skipping Tests, and Other Tips and Tricks

Nuno Maduro recently shared the ->only() method you can attach to tests with PestPHP. I love targeted ways to run and rerun tests efficiently, and this helper sparked an idea to collect the various ways to filter, skip, and target tests in PHP. This post is by no means exhaustive, but I hope to cover the most important techniques. I'll cover both PHPUnit and Pest, where each tool applies. Before we get started, here's a look at the only() method Nuno shared that you can attach to individual tests: it('returns a successful response', function () {     $response = $this->get('/');     $response->assertStatus(200); })->only(); // If you use ->only() with multiple tests it will // run all of those selected tests. it('another test', function () {     // ... })->only(); Using only() acts as a switch that will target individual tests while you focus on writing code and running tests for that feature. Besides the only() helper, both PHPUnit and Pest provide plenty of ways to isolate, skip, and iterate on a selected set of tests. Let's take a look! Filtering Tests Regardless of a project's size, I prefer to run small groups of tests in isolation while I work on a feature. Learning how to select and filter tests in PHP is an invaluable skill for developers to practice with. Pest has many options for filtering tests—including the aforementioned ->only() method—using a combination of code or command line flags. Here are some of the flags Pest offers to filter tests: pest --dirty pest --bail # stop execution on first non-passing test pest --filter 'returns a successful response' pest --retry # reorders higher priority to failed tests pest --group|--exclude-group # Like PHPUnit, filter by test groups. pest --todo # List tests marked as `->todo()` There are other flags and options for test selection in the Pest CLI Reference. PHPUnit also has a variety of ways to filter tests that you can use on the command line: # filter which tests to run phpunit --filter test_the_application_returns_a_successful_response # Group flags phpunit --list-groups # list available groups phpunit --group api phpunit --exclude-group live PHPUnit has a variety of other selection options that you can see by running phpunit --help or visiting the PHP CLI selection documentation. Laravel's Tim MacDonald wrote Tips to Speed up Your Phpunit Tests on Laravel News, which is a resource I recommend to build your test management skills. Pest offers selections similar to PHPUnit and builds some excellent DX helpers on top of PHPUnit that I find invaluable. Skipping Tests Skipping tests is useful when validating your test suite, but know that some tests are either outright broken or a work in progress. A theme I am seeing is that PHPUnit offers the ability to skip tests, and Pest builds on top of that with productive tools that empower you to Brainstorm Tests With PEST Todos and other test-skipping goodies. When I am writing a new feature, I get tons of ideas as I work on the initial features. Ideas come faster than I can write, so I jump to the test file and start creating a to-do checklist right in the code! it('returns a successful response', function () {     $response = $this->get('/');       $response->assertStatus(200); });   it('requires a valid email')->todo(); it('detects Gmail addresses with a "+" as a non-unique email.')->todo(); it('requires a strong password')->todo(); I can then run pest --todo and know exactly where to find new features or tests that I didn't quite finish and want to revisit. PHPUnit has CLI flags you can use to select/skip tests, such as the --exclude-filter or --exclude-group, which are broader. When you want to skip a specific test, you can use the provided markTestIncomplete() method in the test: public function test_the_application_returns_a_successful_response(): void {     $this->markTestIncomplete('it requires a valid email');     $response = $this->get('/');     $response->assertStatus(200); } If you run the test suite, you will get a note that you have one or more incomplete tests. You can list all of the incomplete tests in more detail using the --display-incomplete flag: I interpret incomplete tests to be the closest equivalent to Pest's todo() method. While you can achieve similar using markTestAsSkipped(), I would reserve that for skipping tests that shouldn't run on a target platform or given scenario. Run Tests for Specific PHP or OS Versions If your codebase supports multiple versions of PHP, sometimes it makes sense to skip specific tests on a given set of PHP versions, Operating systems, or extensions. Both Pest and PHPUnit offer flexible support for these needs. PHPUnit has a RequiresPhp attribute you can use to target PHP versions in tests, as well as various operating system attributes: use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; use PHPUnit\Framework\Attributes\RequiresPhp; #[RequiresPhp('<=8.0.0')] #[RequiresOperatingSystemFamily('Windows')] public function test_the_application_returns_a_successful_response(): void {     $response = $this->get('/');     $response->assertStatus(200); } Note: Historically, PHPUnit used the @requires annotation (which is now deprecated) to target multiple types of common preconditions like PHP version, OS, functions, etc. When you run the above test, it is skipped for systems running a PHP version >8.0.0 or OS other than the Windows family. Running the test suite with --display-skipped gives you details on any skipped tests based on these attributes: As part of Pest's Skipping Tests docs, you can use the following methods to skip certain PHP versions, OS versions, etc. it('has home', function () {     // })->skipOnPhp('>=8.0.0'); it('has home', function () {     // })->skipOnWindows(); // or skipOnMac() or skipOnLinux() ...      it('has home', function() {     // })->onlyOnWindows(); // or onlyOnMac() or onlyOnLinux() ... Running a Single Test From Your Editor The last thing to mention is that IDEs offer ways to quickly run individual tests, groups of tests, all tests in one file, etc., with quick command shortcuts. The Better PHPUnit VS Code Extension supports both PHPUnit and Pest, and provides the following features: Run a test method Run a test file Run the entire suite Run a previous test PHPStorm offers a ton of useful ways to run (and rerun) tests with shortcuts and UI icons, making it super easy to run a test from the test file without jumping to the command line: See the PhpStorm documentation for details on setting up testing shortcuts and tools for both PHPUnit and Pest. An honorable mention is the sublime-phpunit plugin that gives you the ability to run Run individual unit tests and files directly from Sublime. What other IDE and text editor tools do you use to automate running tests? Let us know! The post Running a Single Test, Skipping Tests, and Other Tips and Tricks appeared first on Laravel News. Join the Laravel Newsletter to get Laravel articles like this directly in your inbox.

View Third-party Relations in model:show - Now Available in Laravel 11.11
View Third-party Relations in model:show - Now Available in Laravel 11.11

This week, the Laravel team released v11.11, with support for third-party relations in the model:show command, new Collection methods, new cache events, and more. before and after Collection Methods Ryuta Hamasaki contributed before and after methods to Collection and LazyCollection instances Here are examples of the before method from the pull request description: $collection = collect([1, 2, 3, 4, 5, 'name' => 'taylor', 'framework' => 'laravel']); $collection->before(2) // 1 $collection->before('taylor') // 5 $collection->before('laravel') // 'taylor' $collection->before(fn ($value) => $value > 4) // 4 $collection->before(fn ($value) => ! is_numeric($value)) // 5 $collection->before(1) // null $collection->before('not found') // null Here are examples of the after method from the pull request description: $collection = collect([1, 2, 3, 4, 5, 'name' => 'taylor', 'framework' => 'laravel']); $collection->after(1) // 2 $collection->after('taylor') // 'laravel' $collection->after(fn ($value) => $value > 4) // 'taylor' $collection->after(fn ($value) => ! is_numeric($value)) // 'laravel' $collection->after('laravel') // null $collection->after('not found') // null Cache Events Alex Bouma contributed new cache events to the framework that applications can listen to: use Illuminate\Cache\Events\ForgettingKey; use Illuminate\Cache\Events\KeyForgetFailed; use Illuminate\Cache\Events\KeyWriteFailed; // Two public properties: `$this->value` and `$this->seconds` use Illuminate\Cache\Events\RetrievingKey; use Illuminate\Cache\Events\RetrievingManyKeys; // One public property: `$this->keys` use Illuminate\Cache\Events\WritingKey // Two public properties: `$this->value` and `$this->seconds` use Illuminate\Cache\Events\WritingManyKeys; // Three public properties: // `$this->keys`, `$this->values` and `$this->seconds` Support Third-party Relations in model:show Jonas Staudenmeir contributed the ability to include third-party package model relations in the model:show command: The model:show command finds a model's relations by analyzing the code of its methods and looking for $this->hasMany( etc. This doesn't detect third-party relations (like eloquent-has-many-deep). We could build a whole system for packages to hook into, but that would be overkill, IMO. Instead, we can check the method's return type and see if it's a subclass of the base Relation class. Not everybody uses return types, but I hope that most do nowadays. You can learn more about this addition in Pull Request #51807. Session ID Getter Tim MacDonald contributed the Session::id() method to the Session facade: Session::id(); // You can still use `getId()` too: Session::getId(); Timezone and Locale Added to the about Command Amir Khalife Soltani contributed to adding Locale and Timezone values to Laravel's about command. You can now quickly determine what the configured locale and timezone are at a glance with other important environment information: The `about` command with `Timezone` and `Locale` values 422 Unprocessable Content Status Code Dwight Watson contributed updates to the status code method for determining a 422 status code, which is now referred to as 422 Unprocessable Content instead of Unprocessable Entity. The way you interact with asserting a 422 status code hasn't changed: $response = $this->postJson('/example', []); $response->assertUnprocessable(); See RFC 9110: HTTP Semantics and Pull Request #51815 for details. Add Relation::getMorphAlias() Method Dennis Koch contributed a Relation::getMorphAlias() method Since there is a Relation::getMorphedModel() I think it would be beneficial to add the reverse getMorphAlias. This addition is particularly beneficial for testing, as it simplifies assertions with $this->assertDatabaseHas. Developers no longer need to recall the morph alias used: $this->assertDatabaseHas('taskables', [ 'taskable_type' => Relation::getMorphAlias(Document::class), 'taskable_id' => $mitigation->id, 'task_id' => $taskB->id ]); Release notes You can see the complete list of new features and updates below and the diff between 11.10.0 and 11.11.0 on GitHub. The following release notes are directly from the changelog: v11.11.0 [11.x] Add get, write and forget cache events by @stayallive in https://github.com/laravel/framework/pull/51560 [11.x] Add test for Arr::sortRecursiveDesc() method. by @lmottasin in https://github.com/laravel/framework/pull/51716 [11.x] Fix missing table name in db:table command by @benholmen in https://github.com/laravel/framework/pull/51710 Ensure files exist for install:broadcasting by @jasonmccreary in https://github.com/laravel/framework/pull/51719 [11.x] Restore exceptions/errors to test assertion failure messages by @jessarcher in https://github.com/laravel/framework/pull/51725 [11.x] Test Improvements by @crynobone in https://github.com/laravel/framework/pull/51723 [11.x] Add tests for accessible and take method by @saMahmoudzadeh in https://github.com/laravel/framework/pull/51724 Increment the totalJobs property for the BatchFake when add some jobs by @yankewei in https://github.com/laravel/framework/pull/51742 [11.x] Give session ID retrieval the Laravel treatment by @timacdonald in https://github.com/laravel/framework/pull/51732 [11.x] Fix the chunk method to an integer type in the splitIn method by @rookiexxk in https://github.com/laravel/framework/pull/51733 Update:update name method and doc by @mehdi-fathi in https://github.com/laravel/framework/pull/51744 [11.x] Fixes config:publish with dontMergeFrameworkConfiguration() set to true by @crynobone in https://github.com/laravel/framework/pull/51751 Updated phpdoc for Builder::from() by @boris-glumpler in https://github.com/laravel/framework/pull/51767 [11.x] Fixed pop on default Beankstalkd queue when not specifically added by @rinocs in https://github.com/laravel/framework/pull/51759 [11.x] Add before and after methods to Collection by @avosalmon in https://github.com/laravel/framework/pull/51752 [11.x] Change scope for afterCreating and afterMaking callbacks by @jacob418 in https://github.com/laravel/framework/pull/51772 Use numeric literal separator in file rule validation by @AmirKhalifehSoltani in https://github.com/laravel/framework/pull/51781 [11.x] Import Model class for Renderer\Exception by @seriquynh in https://github.com/laravel/framework/pull/51778 [11.x] About command improvement by @AmirKhalifehSoltani in https://github.com/laravel/framework/pull/51791 [11.x] Test abort behavior by @seriquynh in https://github.com/laravel/framework/pull/51800 [11.x] Container shares fixed values/initialized instances instead of singleton closure resolutions by @seriquynh in https://github.com/laravel/framework/pull/51804 [11.x] Fix altering a table that has a column with default 0 on SQLite by @hafezdivandari in https://github.com/laravel/framework/pull/51803 [11.x] Fix typo in VendorPublishCommand by @tamiroh in https://github.com/laravel/framework/pull/51812 [11.x] Fix some typos in the tests by @tamiroh in https://github.com/laravel/framework/pull/51811 [11.x] Add unprocessableContent and update unprocessableEntity by @dwightwatson in https://github.com/laravel/framework/pull/51815 [11.x] Improve Queue::assertNothingPushed() error message by @SjorsO in https://github.com/laravel/framework/pull/51814 [11.x] Add Relation::getMorphAlias() by @pxlrbt in https://github.com/laravel/framework/pull/51809 [11.x] Support third-party relations in model:show command by @staudenmeir in https://github.com/laravel/framework/pull/51807 [11.x] Fix nested rules custom attribute names by @owenandrews in https://github.com/laravel/framework/pull/51805 [11.x] Fix docblock of \Illuminate\Http\Response by @seriquynh in https://github.com/laravel/framework/pull/51823 The post View Third-party Relations in model:show - Now Available in Laravel 11.11 appeared first on Laravel News. Join the Laravel Newsletter to get Laravel articles like this directly in your inbox.

Asserting a JSON Response Structure in Laravel
Asserting a JSON Response Structure in Laravel

When writing tests for API responses in Laravel, it can be useful to validate the structure of the response. Laravel has the fluent assertJson() method, which you can use to verify JSON values in a given test response: it('Returns Arizona sports teams', function () { $this->get('api/teams/arizona') ->assertJson(function (AssertableJson $json) { $json->has('teams', 3); $json->has('teams.0', function (AssertableJson $json) { $json ->where('name', 'Phoenix Suns') ->etc(); }); }); }); Given the above test, here's a static example of the JSON data: { "teams": [ { "name": "Phoenix Suns", "sport": "Basketball" }, { "name": "Arizona Cardinals", "sport": "Football" }, { "name": "Arizona Diamondbacks", "sport": "Baseball" } ] } Our test validates that three teams are listed in Arizona and that the name property exists on the first record. That's excellent for validating the actual values to sample the response using the powerful JSON assertion APIs in Laravel. To complement those assertions, we can also validate the general structure of the whole response: $response->assertJsonStructure([ 'teams' => [ '*' => ['name', 'sport'], ], ]); One caveat to the assertJsonStucture() assertion: if we add a new key in the future, this test will continue to pass. If you require more exactness, you might need to reach for the assertExactJson(). For just generalizing a JSON structure to ensure specific properties exist in the response, assertJsonStructure() can give you confidence that the entire structure contains properties you expect. If you need more extensive assertions around the structure of the JSON, you might also want to reach for whereType() and whereAllType() assertions. Given our earlier example, you could validate the types in your JSON responses using the following: $response->assertJson(function (AssertableJson $json) { $json->has('teams', 3); $json->has('teams.0', function (AssertableJson $json) { $json->whereAllType([ 'name' => 'string', 'sport' => 'string', ]); }); }); Using whereAllType requires us to define types for each and every key in the teams item, unless you use the above with ->etc(): $json->whereAllType([ 'name' => 'string', // 'sport' => 'string', ])->etc(); As mentioned, the above code doesn't assert the whole response and assumes the other teams have the same structure. You could assert each team in the array, and even use Eloquent factory data to validate the response values match. Typically, combining the above assertions will ensure you have the expected JSON response shape, and you can mix in more complicated assertions where needed. See the Laravel Documentation for more examples and useful JSON assertions. The post Asserting a JSON Response Structure in Laravel appeared first on Laravel News. Join the Laravel Newsletter to get Laravel articles like this directly in your inbox.

Create a DateTime from a Timestamp With this New Method Coming to PHP 8.4
Create a DateTime from a Timestamp With this New Method Coming to PHP 8.4

Creating a DateTime from a Unix timestamp will be more convenient in PHP 8.4 with the new createFromTimestamp() method. It will support both a typical Unix timestamp as well as timestamps containing microseconds: $dt = DateTimeImmutable::createFromTimestamp(1718337072); $dt->format('Y-m-d'); // 2024-06-14 $dt = DateTimeImmutable::createFromTimestamp(1718337072.432); $dt->format('Y-m-d h:i:s.u'); // 2024-06-14 03:51:12.432000 With PHP 8.3 and below, you need to use the createFromFormat() method to convert a timestamp into a DateTime or DateTimeImmutable instance. As you can see below, it's not too complicated, but it'll be nice to have a new method to take care of both cases below: $dt = DateTimeImmutable::createFromFormat('U', (string) 1718337072); // DateTimeImmutable @1718337072 {#7948 // date: 2024-06-14 03:51:12.0 +00:00, // } $dt = DateTimeImmutable::createFromFormat('U.u', (string) 1718337072.432); // DateTimeImmutable @1718337072 {#7950 // date: 2024-06-14 03:51:12.432 +00:00, // } For those using the Carbon PHP library, it already has a createFromTimestamp() method available! It is encouraging that PHP is getting this new method at the language level as well! Carbon\Carbon::createFromTimestamp(1718337072.432); // Carbon\Carbon @1718337072 {#7981 // date: 2024-06-14 03:51:12.432 UTC (+00:00), // } Carbon\CarbonImmutable::createFromTimestamp(1718337072); // Carbon\CarbonImmutable @1718337072 {#7999 // date: 2024-06-14 03:51:12.0 UTC (+00:00), // } The post Create a DateTime from a Timestamp With this New Method Coming to PHP 8.4 appeared first on Laravel News. Join the Laravel Newsletter to get Laravel articles like this directly in your inbox.