#laravel #phpunit #config
#laravel #phpunit #конфигурация
Вопрос:
Я искал StackOverflow и в Интернете перепробовал все, что я там нашел, чтобы решить проблему, указанную ниже, но безрезультатно. Ошибка возникает только во время тестирования phpunit. Если запустить приложение Laravel (php artisan serve), оно работает нормально.
Вот подробности:
Я нахожусь на Win7 под управлением cygwin. Я использую composer.json, созданный в проекте php artisan create.
Cygwin (win 7)
Runtime: PHP 7.4.8
PHPUnit 9.3.7 by Sebastian Bergmann and contributors.
Laravel Framework 7.26.0
Вот мой composer.json, который, я думаю, был изначально создан «php artisan create project» или что-то в этом роде.
$ cat composer.json
{
"name": "rubens-gomes/rubens-gomes.com",
"type": "project",
"description": "rubens-gomes.com Web Site",
"homepage": "https://rubens-gomes.com",
"keywords": [
"framework",
"laravel"
],
"license": "PROPRIETARY",
"authors": [
{
"name": "Rubens Gomes",
"email": "rubens.s.gomes@gmail.com",
"homepage": "https://rubens-gomes.com",
"role": "Developer"
}
],
"support": {
"email": "rubens.s.gomes@gmail.com"
},
"require": {
"php": ">=7.4",
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^2.0",
"google/recaptcha": "^1.2",
"guzzlehttp/guzzle": "^6.3",
"laravel/framework": "^7.24",
"laravel/tinker": "^2.0"
},
"require-dev": {
"facade/ignition": "^2.0",
"fzaninotto/faker": "^1.9.1",
"mockery/mockery": "^1.3.1",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^9.2"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"autoload": {
"psr-4": {
"App\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
"autoload-dev": {
"psr-4": {
"Tests\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"post-autoload-dump": [
"Illuminate\Foundation\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install": [
"@php -r "file_exists('.env') || copy('.env.example', '.env');""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"post-update-cmd": "@composer dump-autoload"
}
}
Ниже мой phpunit.xml . Я пробовал другой загрузчик, но безрезультатно.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
<!-- bootstrap="vendor/autoload.php" -->
bootstrap="bootstrap/app.php"
colors="true"
verbose="true">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
Вот фатальная ошибка phpunit. Я не так сильно обеспокоен тем, что мой тестовый пример не выполняется ниже. Основная проблема заключается в неустранимой ошибке «конфигурация не найдена …»
$ php artisan test
Warning: TTY mode is not supported on Windows platform.
PASS TestsUnitExampleTest
✓ basic test
FAIL TestsUnitappHttpControllersContactControllerTest
✕ fail to validate email
Tests: 1 failed, 1 passed, 1 pending
Failed asserting that exception of type "ErrorException" matches expected exception "IlluminateValidationValidationException". Message was: "dns_get_record(): DNS Query failed" at D:gitprojsphprubens-gomesvendoreguliasemail-validatorsrcValidationDNSCheckValidation.php:121 D:gitprojsphprubens-gomesvendoreguliasemail-validatorsrcValidationDNSCheckValidation.php:107 D:gitprojsphprubens-gomesvendoreguliasemail-validatorsrcValidationDNSCheckValidation.php:80 D:gitprojsphprubens-gomesvendoreguliasemail-validatorsrcValidationMultipleValidationWithAnd.php:65 D:gitprojsphprubens-gomesvendoreguliasemail-validatorsrcEmailValidator.php:37 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationConcernsValidatesAttributes.php:666 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationValidator.php:547 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationValidator.php:370 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationValidator.php:401 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationValidator.php:444 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateValidationFactory.php:136 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateFoundationProvidersFoundationServiceProvider.php:58 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateSupportTraitsMacroable.php:111 D:gitprojsphprubens-gomesappHttpControllersContactController.php:90 D:gitprojsphprubens-gomestestsUnitappHttpControllersContactControllerTest.php:43 .
at D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkConstraintConstraint.php:121
117| if (!empty($description)) {
118| $failureDescription = $description . "n" . $failureDescription;
119| }
120|
> 121| throw new ExpectationFailedException(
122| $failureDescription,
123| $comparisonFailure
124| );
125| }
1 D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkConstraintConstraint.php:55
PHPUnitFrameworkConstraintConstraint::fail(Object(ErrorException), "")
2 D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkAssert.php:2331
PHPUnitFrameworkConstraintConstraint::evaluate(Object(ErrorException), "")
PHP Fatal error: Uncaught ReflectionException: Class config does not exist in D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateContainerContainer.php:809
Stack trace:
#0 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateContainerContainer.php(809): ReflectionClass->__construct('config')
#1 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateContainerContainer.php(691): IlluminateContainerContainer->build('config')
#2 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateFoundationApplication.php(796): IlluminateContainerContainer->resolve('config', Array, true)
#3 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateContainerContainer.php(637): IlluminateFoundationApplication->resolve('config', Array)
#4 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateFoundationApplication.php(781): IlluminateContainerContainer->make('config', Array)
#5 D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateC in D:gitprojsphprubens-gomesvendorlaravelframeworksrcIlluminateContainerContainer.php on line 811
PHP Stack trace:
PHP 1. {main}() D:gitprojsphprubens-gomesvendorphpunitphpunitphpunit:0
PHP 2. PHPUnitTextUICommand::main($exit = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitphpunit:61
PHP 3. PHPUnitTextUICommand->run($argv = *uninitialized*, $exit = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcTextUICommand.php:100
PHP 4. PHPUnitTextUITestRunner->run($suite = *uninitialized*, $arguments = *uninitialized*, $warnings = *uninitialized*, $exit = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcTextUICommand.php:147
PHP 5. PHPUnitFrameworkTestSuite->run($result = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcTextUITestRunner.php:671
PHP 6. PHPUnitFrameworkTestSuite->run($result = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestSuite.php:665
PHP 7. PHPUnitFrameworkTestSuite->run($result = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestSuite.php:665
PHP 8. TestsUnitappHttpControllersContactControllerTest->run($result = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestSuite.php:665
PHP 9. PHPUnitFrameworkTestResult->run($test = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestCase.php:880
PHP 10. PHPUnitFrameworkTestResult->addFailure($test = *uninitialized*, $e = *uninitialized*, $time = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestResult.php:894
PHP 11. NunoMaduroCollisionAdaptersPhpunitPrinter->addFailure($testCase = *uninitialized*, $error = *uninitialized*, $time = *uninitialized*) D:gitprojsphprubens-gomesvendorphpunitphpunitsrcFrameworkTestResult.php:391
PHP 12. NunoMaduroCollisionAdaptersPhpunitStyle->writeError($state = *uninitialized*, $throwable = *uninitialized*) D:gitprojsphprubens-gomesvendornunomadurocollisionsrcAdaptersPhpunitPrinterContents.php:114
Below is controller being tested. Noticed that this is very basic code and testing just to see if things work.
And BTW I am learning Laravel.
$ cat app/Http/Controllers/ContactController.php
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use IlluminateSupportMessageBag;
use IlluminateSupportFacadesLog;
use ReCaptchaReCaptcha;
/**
* Controller to handle incoming "/contact" form requests.
*
* @author Rubens Gomes <rubens.s.gomes@gmail.com>
* @copyright 2020 Rubens Gomes
*/
final class ContactController extends Controller
{
/** @var array containing fields to be used on the view.*/
private $data;
/** @var array contact form validation rules. */
private $formRules;
/**
*
* @var ReCaptchaReCaptcha instance of Google ReCaptcha to be injected
* during unit testing. If no instance is injected a new one is created.
*/
private $recaptcha;
/**
* The default constructor.
*
* @param ReCaptcha $rc The Google ReCaptcha object.
*/
public function __construct(ReCaptcha $rc = null)
{
if ($rc === null) {
$this->recaptcha = new ReCaptcha(config('services.recaptcha.secret_key'));
} else {
$this->recaptcha = $rc;
}
$this->data = [
'pageId' => 'contact',
'homeHref' => '/#home',
'aboutHref' => '/#about',
'contactHref' => '#contact'
];
$this->formRules = [
'email' => 'required|email:dns',
'name' => 'required',
'msg' => 'required',
'g-recaptcha-response' => 'required'
];
Log::debug(__CLASS__ . " constructed");
}
public function __destruct()
{
Log::debug(__CLASS__ . " destructed");
}
/**
* Process the incoming GET request to render the contact page.
*
* @return IlluminateViewView The contact main page view.
*/
public function index()
{
Log::debug(__CLASS__ . ":" . __FUNCTION__);
return view('contact', $this->data);
}
/**
* Handles the contact message form POST submit by validating the form
* fields, validating the captcha and then sending an email message with
* the information provided in the form.
*
* @param IlluminateHttpRequest $request
* The HTTP request
* @return IlluminateViewView The contact main page view.
*/
public function sendmsg(Request $request)
{
Log::debug(__CLASS__ . ":" . __FUNCTION__);
// validate input contact fields
Log::debug('validating contact form');
$request->validate($this->formRules);
// validate the captcha
$captcha = $request->input(config('services.recaptcha.resp_parm'));
Log::debug('validating captcha...');
$response = $this->recaptcha->verify($captcha);
if (! $response->isSuccess()) {
Log::warning('failed to authenticate captcha');
$captchaError = new MessageBag();
$captchaError->add('recaptcha_error', 'Failed to authenticate captcha');
return view('contact', $this->data)->withErrors($captchaError);
}
return redirect()->back()->withSuccess('Your message has been successfully submitted.');
}
}
/******************************************************************************/
// EOF
And here is my controller test code:
$ cat tests/Unit/app/Http/Controllers/ContactControllerTest.php
<?php
namespace TestsUnitappHttpControllers;
use AppHttpControllersContactController;
use IlluminateHttpRequest;
use IlluminateValidationValidationException;
use TestsTestCase;
use ReCaptchaReCaptcha;
class ContactControllerTest extends TestCase
{
/** @var AppHttpControllersContactController The controller being tested */
private $controller;
/** @var ReCaptchaReCaptcha The Google ReCaptcha being doubled */
private $rcStub;
public function setUp(): void
{
parent::setUp();
$this->rcStub = $this->createStub(ReCaptcha::class);
$this->controller = new ContactController($this->rcStub);
}
public function tearDown(): void
{
parent::tearDown();
}
public function testFailToValidateEmail()
{
$this->expectException(ValidationException::class);
$form = [
'email' => 'rubens.s.gomes @ gmail.com',
'msg' => 'This is a test.nRubens Gomes',
'name' => 'Rubens Gomes',
'g-recaptcha-response' => 'hello google captcha'
];
$request = Request::create('/contact/sendmsg', 'POST', $form);
$this->controller->sendmsg($request);
}
}
Вот мой файл .env:
$ cat .env
APP_NAME="Laravel"
APP_ENV="local"
APP_KEY="base64:mJmYLlc2V43AKfa3u7s1po7RHyPDajRZIB4pIArTyjg="
APP_DEBUG=true
APP_URL="http://localhost"
LOG_CHANNEL="stack"
DB_CONNECTION="mysql"
DB_HOST="127.0.0.1"
DB_PORT=3306
DB_DATABASE="laravel"
DB_USERNAME="root"
DB_PASSWORD="root"
BROADCAST_DRIVER="log"
CACHE_DRIVER="file"
QUEUE_CONNECTION="sync"
SESSION_DRIVER="file"
SESSION_LIFETIME=120
REDIS_HOST="127.0.0.1"
REDIS_PASSWORD="null"
REDIS_PORT=6379
MAIL_MAILER="smtp"
MAIL_HOST="smtp.mailtrap.io"
MAIL_PORT=2525
MAIL_USERNAME="null"
MAIL_PASSWORD="null"
MAIL_ENCRYPTION="null"
MAIL_FROM_ADDRESS="null"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
AWS_DEFAULT_REGION="us-east-1"
AWS_BUCKET=""
PUSHER_APP_ID=""
PUSHER_APP_KEY=""
PUSHER_APP_SECRET=""
PUSHER_APP_CLUSTER="mt1"
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
RECAPTCHA_DOMAIN="NOT_DISPLAYED"
RECAPTCHA_SITE_KEY="NOT_DISPLAYED"
RECAPTCHA_SECRET_KEY="NOT_DISPLAYED"
RECAPTCHA_OWNER="rubens.s.gomes@gmail.com"
RECAPTCHA_VERSION="V2"
Комментарии:
1. Не могли бы вы поделиться своим контроллером и тестовым кодом контроллера?
2. Вы можете найти множество идей здесь
3. Я попробовал предложение «php artisan config: cache» в одном из сообщений на github. Я увидел улучшение (на одну трассировку стека меньше) в phpunit. Но все еще есть один случай «PHP Fatal error: Uncaught ReflectionException: конфигурация класса не существует в …». Я обновил свой первоначальный пост последней информацией 27.08.2020.
Ответ №1:
Я переписал весь приведенный выше код. И теперь он работает нормально. Ниже приведены фрагменты некоторого нового кода.
composer.json:
$ cat composer.json
{
"name" : "rubens-gomes/rubens-gomes.com",
"type" : "project",
"description" : "rubens-gomes.com Web Site",
"homepage" : "https://rubens-gomes.com",
"keywords" : [
"framework",
"laravel"
],
"license" : "PROPRIETARY",
"authors" : [{
"name" : "Rubens Gomes",
"email" : "rubens.s.gomes@gmail.com",
"homepage" : "https://rubens-gomes.com",
"role" : "Developer"
}
],
"support" : {
"email" : "rubens.s.gomes@gmail.com"
},
"require" : {
"php" : ">=7.4",
"fideloper/proxy" : "^4.2",
"fruitcake/laravel-cors" : "^2.0",
"google/recaptcha" : "^1.2",
"guzzlehttp/guzzle" : "^6.3",
"laravel/framework" : "^7.24",
"laravel/tinker" : "^2.0"
},
"require-dev" : {
"facade/ignition" : "^2.0",
"fzaninotto/faker" : "^1.9.1",
"mockery/mockery" : "^1.3.1",
"nunomaduro/collision" : "^4.1",
"phpunit/phpunit" : "^8.5"
},
"config" : {
"optimize-autoloader" : true,
"preferred-install" : "dist",
"sort-packages" : true
},
"extra" : {
"laravel" : {}
},
"autoload" : {
"psr-4" : {
"App\" : "app/"
},
"classmap" : [
"database/seeds",
"database/factories"
]
},
"autoload-dev" : {
"psr-4" : {
"Tests\" : "tests/"
}
},
"minimum-stability" : "dev",
"prefer-stable" : true,
"scripts" : {
"post-autoload-dump" : [
"Illuminate\Foundation\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install" : "@php -r "file_exists('.env') || copy('.env.example', '.env');"",
"post-create-project-cmd" : "@php artisan key:generate --ansi",
"post-update-cmd" : "@composer dump-autoload"
}
}
phpunit.xml:
$ cat phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
To run the unit tests configured in this PHPUnit XML configuration file:
php artisan test -vvv
@author Rubens Gomes <rubens.s.gomes@gmail.com>
@link https://rubens-gomes.com
-->
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
bootstrap="bootstrap/app.php"
colors="true"
verbose="true">
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<php>
<server name="APP_ENV" value="testing"/>
</php>
</phpunit>
.env:
$ cat .env
APP_NAME="rubens-gomes.com"
APP_ENV="testing"
APP_KEY="base64:mJmYLlc2V43AKfa3u7s1po7RHyPDajRZIB4pIArTyjg="
APP_DEBUG=true
APP_URL="http://localhost:8080"
LOG_CHANNEL="stdout"
MAIL_MAILER="smtp"
MAIL_HOST="smtp.gmail.com"
MAIL_PORT=465
MAIL_USERNAME="NOT_DISPLAYED"
MAIL_PASSWORD="NOT_DISPLAYED"
MAIL_FROM_ADDRESS="NOT_DISPLAYED"
MAIL_FROM_NAME="${APP_NAME}"
RECAPTCHA_DOMAIN="rubens-gomes.com"
RECAPTCHA_SITE_KEY="NOD_DISPLAYED"
RECAPTCHA_SECRET_KEY="NOT_DISPLAYED"
RECAPTCHA_OWNER="rubens.s.gomes@gmail.com"
RECAPTCHA_VERSION="V2"
тестовый вывод:
$ php artisan test -vvv
Warning: TTY mode is not supported on Windows platform.
PASS TestsUnitExampleTest
✓ basic test
RUNS TestsUnitappHttpControllersContactControllerTest
• fail due to invalid form
Tests: 4 passed, 17 pending
[2020-08-30T05:29:18.173039 00:00] testing.DEBUG: creating contact instance [] []
RUNS TestsUnitappHttpControllersContactControllerTest
• ensure sucess response for valid form
PASS TestsUnitappHttpControllersContactControllerTest
✓ ensure request to index page works
✓ fails due to wrong resource
✓ fail due to post method not allowed for index page
✓ fail due to invalid form
✓ ensure sucess response for valid form
PASS TestsUnitappHttpControllersHomeControllerTest
✓ ensure request to index page works
✓ fails due to wrong resource
PASS TestsUnitappMailContactRequestMailableTest
✓ fail due to null contact
✓ ensure constructor works
✓ ensure build works
PASS TestsUnitappMailContactResponseMailableTest
✓ fail due to null contact
✓ ensure constructor works
✓ ensure build works
RUNS TestsUnitappModelContactTest
• fail due to invalid email
RUNS TestsUnitappModelContactTest
• fail due to invalid email domain
PASS TestsUnitappModelContactTest
✓ fail due to invalid email
✓ fail due to invalid email domain
✓ ensure contact is created
✓ ensure email is not empty
✓ ensure name is not empty
✓ ensure msg is not empty
PASS TestsFeatureExampleTest
✓ basic test
Tests: 21 passed
Time: 4.93s
ContactControllerTest.php:
<?php
namespace TestsUnitappHttpControllers;
use AppHttpControllersContactController;
use AppMailContactRequestMailable;
use IlluminateHttpRequest;
use IlluminateSupportFacadesMail;
use ReCaptchaReCaptcha;
use TestsTestCase;
class ContactControllerTest extends TestCase
{
/** @var AppHttpControllersContactController The controller being tested */
private $controller;
/** @var ReCaptchaReCaptcha The Google ReCaptcha being doubled */
private $rcStub;
/** @var array valid post form data for testing purposes */
private const VALID_FORM = [
'email' => 'rubens.s.gomes@gmail.com',
'msg' => 'This is a test.nRubens Gomes',
'name' => 'Rubens Gomes',
'g-recaptcha-response' => 'hello google captcha'
];
/** @var array invalid post form data for testing purposes */
private const INVALID_FORM = [
'email' => 'rubens.s.gomes@gmail.com',
'msg' => 'This is a test.nRubens Gomes',
'name' => '',
'g-recaptcha-response' => 'hello google captcha'
];
public function setUp(): void
{
parent::setUp();
$this->rcStub = $this->createStub(ReCaptcha::class);
$this->controller = new ContactController($this->rcStub, Mail::fake());
}
public function tearDown(): void
{
parent::tearDown();
}
public function testEnsureRequestToIndexPageWorks()
{
$response = $this->get('/contact/');
$this->assertTrue($response->isOk());
}
public function testFailsDueToWrongResource()
{
$response = $this->get('/contact/hello');
$response->assertStatus(404);
}
public function testFailDueToPostMethodNotAllowedForIndexPage()
{
$response = $this->post('/contact/');
$response->assertStatus(405);
}
public function testFailDueToInvalidForm()
{
$response = $this->post('/contact/sendmsg', self::INVALID_FORM);
$response->assertRedirect();
}
// unit testing controller
public function testEnsureSucessResponseForValidForm()
{
$request = Request::create('/contact/sendmsg', 'POST', self::VALID_FORM);
$rcResp = new ReCaptchaResponse(TRUE);
$this->rcStub->method('verify')->willReturn($rcResp);
$this->controller->sendmsg($request);
Mail::assertSent(ContactRequestMailable::class, 1);
}
}
ContactController.php
<?php
namespace AppHttpControllers;
use AppMailContactRequestMailable;
use AppModelContact;
use IlluminateHttpRequest;
use IlluminateSupportMessageBag;
use IlluminateSupportFacadesLog;
use IlluminateSupportFacadesMail;
use ReCaptchaReCaptcha;
/**
* Controller to handle incoming "/contact" form requests.
*
* @author Rubens Gomes <rubens.s.gomes@gmail.com>
*/
final class ContactController extends Controller
{
/** @var array containing fields to be used in the view.*/
private const VIEW_DATA = [
'pageId' => 'contact',
'homeHref' => '/#home',
'aboutHref' => '/#about',
'contactHref' => '#contact'
];
/** @var IlluminateSupportFacadesMail instance of mail service. */
private $mailer;
/** @var ReCaptchaReCaptcha instance of Google ReCaptcha. */
private $recaptcha;
/**
* The default constructor.
*
* @param ReCaptcha $rc
* The Google ReCaptcha object.
*/
public function __construct(ReCaptcha $rc = null)
{
if ($rc === null) {
$this->recaptcha = new ReCaptcha(config('services.recaptcha.secret_key'));
} else {
// used during unit testing to inject a test double object
$this->recaptcha = $rc;
}
}
/**
* Process the incoming GET request to render the contact page.
*
* @return IlluminateViewView The contact main page view.
*/
public function index()
{
return view('contact', self::VIEW_DATA);
}
/**
* Handles the contact message form POST submit by validating the form
* fields, validating the captcha and then sending an email message with
* the information provided in the form.
*
* @param IlluminateHttpRequest $request
* The HTTP request
* @return IlluminateViewView The contact main page view.
*/
public function sendmsg(Request $request)
{
// validate and create contact
$data = [
'name' => $request->input('name'),
'email' => $request->input('email'),
'msg' => $request->input('msg')
];
$contact = null;
try {
Log::debug('creating contact instance');
$contact = new Contact($data['name'], $data['email'], $data['msg']);
} catch (InvalidArgumentException $ex) {
Log::error('failed to create contact', $data);
return redirect()->back()
->withException($ex)
->withErrors($ex->getMessage());
}
// validate the captcha
$captcha = $request->input(config('services.recaptcha.resp_parm'));
Log::debug('validating captcha', ['captcha' => $captcha]);
$response = $this->recaptcha->verify($captcha);
if (! $response->isSuccess()) {
Log::warning('failed to authenticate captcha', ['captcha' => $captcha]);
$captchaError = new MessageBag();
$captchaError->add('recaptcha_error', 'Failed to authenticate captcha');
return redirect()->back()->withErrors($captchaError);
}
// send message by email
Log::debug('sending email', ['email' => $contact->getEmail() ]);
$reqMail = new ContactRequestMailable($contact);
Mail::to($contact->getEmail())->send($reqMail);
return redirect()->back()->withSuccess('Your message has been successfully submitted.');
}
}
/******************************************************************************/
// EOF
Contact.php :
<?php
namespace AppModel;
use IlluminateSupportFacadesLog;
use IlluminateSupportFacadesValidator;
/**
* A data model object to represent a contact (e.g., from the contact form).
*
* @author Rubens Gomes <rubens.s.gomes@gmail.com>
*/
class Contact
{
/** @var array $validationRules The rules for validating input data */
private static $validationRules = [
'name' => 'required|max:100',
'email' => 'required|email:rfc,dns',
'msg' => 'required|max:1000',
];
/** @var string $name The contact name */
private $name;
/** @var string $email The contact email address */
private $email;
/** @var string $msg The contact message */
private $msg;
/**
* Default constructor.
*
* @param string $name
* The non-blank contact name.
* @param string $email
* The non-blank contact email.
* @param string $msg
* The non-blank contact message.
* @throws InvalidArgumentException if any of the arguments is not valid.
*/
public function __construct($name, $email, $msg)
{
$data = [
'name' => $name,
'email' => $email,
'msg' => $msg
];
$validator = Validator::make($data, self::$validationRules);
if($validator->fails()) {
Log::error("name or email invalid", $data);
throw new InvalidArgumentException("Invalid argument: " . $validator->errors());
}
$this->name = $name;
$this->email = $email;
$this->msg = $msg;
}
public function getEmail() : string
{
return $this->email;
}
public function getMessage() : string
{
return $this->msg;
}
public function getName() : string
{
return $this->name;
}
}
/******************************************************************************/
// EOF
ContactRequestMailable.php:
<?php
namespace AppMail;
use AppModelContact;
use IlluminateMailMailable;
/**
* Mailable used to send email of message in contact form.
*
* @author Rubens Gomes
*/
class ContactRequestMailable extends Mailable
{
private const SUBJECT = "Rubens Gomes - Contact";
/** @var Contact The contact instance. */
private $contact;
/**
* Default constructor
*
* @param Contact $contact
* the non-null and valid contact instance.
* @throws InvalidArgumentException if any of the arguments is not valid.
*/
public function __construct($contact = null)
{
if (is_null($contact)) {
throw new InvalidArgumentException("contact cannot be null.");
}
$this->contact = $contact;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->subject(self::SUBJECT)
->locale('en')
->from(config('mail.from.address'), config('mail.from.name'))
->to(config('mail.from.address'), config('mail.from.name'))
->view('emails.contact-request')
->with([
'name' => $this->contact->getName(),
'email' => $this->contact->getEmail(),
'msg' => $this->contact->getMessage()
]);
}
}
/******************************************************************************/
// EOF```
Ответ №2:
У меня эта проблема в тестах @depens. Я очистил удаление, чтобы исправить это.
protected function tearDown() :void
{
// Don't clear test environment between tests
}