Laravel 5 How to validate a unique customer name under each Activity when save - laravel-5.3

I had three model: Activity Model, Customer Model and Customeritem Model
How to do the validation checking in store function whereby the customer name should be UNIQUE in each Activity?
Below is each migration files
Activity Model
public function up()
{
Schema::create('activities', function (Blueprint $table) {
$table->increments('id');
$table->string('activityName');
$table->string('activityCode');
$table->string('activityVenue');
$table->timestamps();
});
}
Customer Model
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->increments('id');
$table->integer('activities_id')->unsigned()->default(0);
$table->foreign('activities_id')->references('id')->on('activities')->onDelete('cascade');
$table->text('remark')->nullable();
$table->timestamps();
});
}
Customeritem Model
public function up()
{
Schema::create('customeritems', function (Blueprint $table) {
$table->increments('id');
$table->integer('customers_id')->unsigned()->default(0);
$table->foreign('customers_id')->references('id')->on('customers')->onDelete('cascade');
$table->string('customerName');
$table->integer('customerAge')->unsigned();
$table->timestamps();
});
}
Controller for Store new entry
public function store(Request $request)
{
$rules = array(
'customerName' => 'required|distinct',
);
$messages = array(
'customerName.required'=>'Customer Name is required',
'customerName.distinct'=>'Customer Name has a duplicate value.',
);
Here how to do validation for unique customerName for each activity?

Related

Symfony Zenstruck Foundry embedded entity without duplicated property

I have an entity MultiChannel that has a OneToMany relation with SalesChannel.
The restriction is that MultiChannel cannot have 2 SalesChannels that have the same name property.
Initially I had created the Story below, but that will endup with SalesChannels that have the same name.
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => SalesChannelFactory::randomRange(1,3),
];
});
}
}
Then I created a SalesChannelStory as below:
App/Tests/Story/SalesChannelStory
final class SalesChannelStory extends Story
{
public function build(): void
{
$this->addToPool('name1', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[0]])->many(50));
$this->addToPool('name2', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[1]])->many(50));
$this->addToPool('name3', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[2]])->many(50));
$this->addToPool('name4', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[3]])->many(50));
}
}
The intention was to do something as below on MultiChannelStory, in somewhat pseudo code, so that
I could insert only uniquely named SalesChannel into MultiChannel:
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => $this->getUniqueNamed(),,
];
});
}
}
private function getUniqueNamed(): \App\Entity\Onetomanybi|\Zenstruck\Foundry\Proxy
{
// get up to 4 SalesChannel without the property `name` being repeated.
$items = [SalesChannelStory::getRandom('name1'), SalesChannelStory::getRandom('name2')];
return $items;
//return SalesChannelStory::getRandom('name1');
}
But that does not work.
Note that MultiChannel has to have at least one SalesChannel, up to as many SalesChannel exists, or 4 currently.

Phpunit testing callback functions when passing them to a stub method

Here is the method to test.
public function performPoolRequest(RecreationRequestsCollection $requests): RecreatedPaymentsPoolReading
{
$count_request = count($requests);
if($count_request) {
$pool_recreate_payments = new RecreatedPaymentsPool();
$this->http_client->sendPoolRequest(
$this->generateRequests($requests),
$count_request,
function (ResponseInterface $response, $index) use ($requests, $pool_recreate_payments) {
$this->successHandler($response, $requests, $index, $pool_recreate_payments);
},
function (BadResponseException $reason, $index) use ($requests, $pool_recreate_payments) {
$this->failureHandler($reason, $requests, $index, $pool_recreate_payments);
}
);
return $pool_recreate_payments;
} else {
throw new PoolRequestException('Incorrect amount of requests: ' . $count_request);
}
}
Difficulties arose with this piece of code:
$this->http_client->sendPoolRequest(
$this->generateRequests($requests),
$count_request,
function (ResponseInterface $response, $index) use ($requests, $pool_recreate_payments) {
$this->successHandler($response, $requests, $index, $pool_recreate_payments);
},
function (BadResponseException $reason, $index) use ($requests, $pool_recreate_payments) {
$this->failureHandler($reason, $requests, $index, $pool_recreate_payments);
}
);
I made a mock object $this->http_client
But I don't know how to test methods in the argumets ($this->successHandler, $this->failureHandler, this->generateRequests($requests)) that are sent to the method sendPoolRequest.
All of these methods are protected. I understand how to test them using a reflection object, but I want to know if there is an option to test them within a single test by checking the values in $ pool_recreate_payments.
You have to fake what the http client is doing in some way. That means: actually calling the callback functions. While it might be possible to do that with a PHPUnit mock object, writing own test doubles is often easier.
Here are a few examples to get you started.
public function testAllFailing()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
$errorHandler(new BadResponseException(/*...*/), $index);
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
public function testAllSucceeding()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
$successHandler(new Response(/*...*/), $index);
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
public function testEveryOtherFails()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
if ($index % 2 === 0) {
$successHandler(new Response(/*...*/), $index);
} else {
$errorHandler(new BadResponseException(/*...*/), $index);
}
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
Since Guzzle is used as the http client, I decided to use its capabilities in terms of creating stubs for the response object. Here is a link to the documentation Guzzle documentation. The solution turned out to be simple and allowed us to extensively test the business logic of the response.

SilverStripe: How to set/ specify the icon for GridField custom action button

I am working on a SilverStripe project. In my project, I am trying to create a GridField custom button. I followed the official documentation. Following is the class form the SilverStripe official page.
class GridFieldCustomAction implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem
{
public function getTitle($gridField, $record, $columnName)
{
return 'Custom action';
}
public function getCustomAction($gridField, $record)
{
if (!$record->canEdit()) {
return;
}
return GridField_FormAction::create(
$gridField,
'CustomAction'.$record->ID,
'Custom action',
"docustomaction",
['RecordID' => $record->ID]
)->addExtraClass(
'action-menu--handled'
);
}
public function getExtraData($gridField, $record, $columnName)
{
$field = $this->getCustomAction($gridField, $record);
if (!$field) {
return;
}
return $field->getAttributes();
}
public function getGroup($gridField, $record, $columnName)
{
return GridField_ActionMenuItem::DEFAULT_GROUP;
}
public function augmentColumns($gridField, &$columns)
{
if (!in_array('Actions', $columns)) {
$columns[] = 'Actions';
}
}
public function getColumnAttributes($gridField, $record, $columnName)
{
return ['class' => 'grid-field__col-compact'];
}
public function getColumnMetadata($gridField, $columnName)
{
if ($columnName === 'Actions') {
return ['title' => ''];
}
}
public function getColumnsHandled($gridField)
{
return ['Actions'];
}
public function getColumnContent($gridField, $record, $columnName)
{
$field = $this->getCustomAction($gridField, $record);
if (!$field) {
return;
}
return $field->Field();
}
public function getActions($gridField)
{
return ['docustomaction'];
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
{
if ($actionName !== 'docustomaction') {
return;
}
// perform your action here
// output a success message to the user
Controller::curr()->getResponse()->setStatusCode(
200,
'Do Custom Action Done.'
);
}
}
I am struggling to add the custom icon for the button or specify the style class of the button. I can change the column class name. But I cannot find a way for the button. How can I do that?
you can achieve this using ->setAttribute('classNames', 'font-icon-<your-icon>');
i.e. for "edit" icon the code would looks like this:
return GridField_FormAction::create(
$gridField,
'CustomAction'.$record->ID,
'Custom action',
"docustomaction",
[
'RecordID' => $record->ID
]
)
->addExtraClass('action-menu--handled')
->setAttribute('classNames', 'font-icon-edit');
You can find all available icons on this page:
https://gbaumeister.github.io/ss4-icons/

Base table or view not found: 1146 Table Laravel 5.7

Im getting this error when I try to save data to mysql using Laravel 5, other forms and save() methods work fine but this one:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'datatest.about_category' doesn't exist (SQL: insert into about_category (about_id, category_id) values (11, 4))
Here is my Controller store method:
public function store(AboutRequest $request)
{
$about = new About();
$about->title = $request->title;
$about->body = $request->body;
$about->save();
$about->categories()->attach(request('category'));
return redirect(route('abouts.create'));
}
And here is my model:
About.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class About extends Model
{
public $table = "abouts";
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
Category .php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = "categories";
public $fillable = ['id' , 'name'];
public function abouts(){
return $this->belongsToMany(About::class);
}
}
For abouts table
public function up()
{
Schema::create('abouts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
For categories table
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
Your many-to-many relationship requires three tables: abouts, categories, and about_category. You haven't created the about_category table:
Schema::create('about_category', function (Blueprint $table) {
$table->integer('about_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->foreign('about_id')->references('id')->on('abouts');
$table->foreign('category_id')->references('id')->on('categories');
});

FluentValidation set validator on collection with Ruleset

I'm creating a POST Rest API(ASP.NET Web API) to perform write operations,so have to validate data before inserting them into Database.I'm pretty new to using FluentValidation to validate the data.
Suppose below are classes that I have and need to validate.
public class Listing
{
public Type Type { get; set; }
public Source Source { get; set; }
public List<ListingDetails> ListingDetails { get;set; }
}
public class ListingDetails
{
public int Id{ get; set; }
public ListingStatus Status { get; set; }
}
public enum ListingStatus
{
Active = 1,
Converted = 2,
LostToCompetitor = 3
}
Below code is responsible for validating the status based on the provided ruleset.
public class ListingStatusValidator : AbstractValidator<ListingDetails>
{
public ListingStatusValidator()
{
RuleSet("A", () =>
{
RuleFor(x=>x.InquiryId).GreaterThan(0);
});
RuleSet("B", () =>
{
RuleFor(x => x.Status).IsInEnum().NotEqual(ListingStatus.Active);
});
RuleSet("C", () =>
{
RuleFor(x => x.Status).IsInEnum();
});
}
}
Below is the piece of code used to validatelisting.
public class ListingValidator : AbstractValidator<Listing>
{
public ListingValidator()
{
RuleSet("common", () =>
{
When(x => x.ListingDetails != null && x.ListingDetails.Count <= 1000, () =>
RuleForEach(x => x.ListingDetails).SetValidator(new ListingStatusValidator()));
});
}
}
Now to validate we will call validate method of the validator like below.
var validation = new ListingValidator().Validate(listing,ruleSet:"common");
Is it possible to pass ruleset when validating using setvalidator on collection of objects.Please see below snippet to understand what I'm trying to achieve.
public class ListingValidator : AbstractValidator<Listing>
{
public ListingValidator()
{
When(x => x.ListingDetails != null && x.ListingDetails.Count <= 1000, () =>
RuleForEach(x => x.ListingDetails).SetValidator(new ListingStatusValidator(),ruleset:"A,B,C"));
}
}
You can execute more then one RuleSet using RulesetValidatorSelector
var validation = new ListingValidator()
.Validate(listing, new RulesetValidatorSelector("common", "A", "B", "C"));
In this case you don't need to specify RuleSets for ListingStatusValidator, RuleSets from ListingValidator will be passed to nested validator.

Resources