Laravel Feature Test - Inserting Data - testing

I have a metadata table and need to test inserting data:
public function test_insert_unique_data()
{
$response = Metadata::create([
'metable_id' => '1',
'metable_type' => File::class,
'type' => 'resolution',
'key' => 'width',
'value' => 1000,
]);
$response->assertCreated();
}
This is the migration for the table:
Schema::create(..., function (Blueprint $table) {
$table->id();
$table->bigInteger('metable_id')->unsigned()->index();
$table->string('metable_type')->index();
$table->string('type')->default('default');
$table->string('key')->index();
$table->text('value');
$table->timestamps();
});
It's failing every time so I can only assume the test is written wrong. Any pointers please?

Why not just use a factory? They have all sorts of assertions in their Database testing section.
Unless there's a reason for it, every testing that uses any models I'm seeing in modern Laravel (I come from Laravel 3-5 days) is using factories.

I don't know about this assertCreated function but I know of something similar:
public function test_insert_unique_data()
{
$metadata = Metadata::create([
'metable_id' => '1',
'metable_type' => File::class,
'type' => 'resolution',
'key' => 'width',
'value' => 1000,
]);
$this->assertModelExists($metadata);
}

Related

Laravel 5.6 - creation user not working

my application used to working well with registration user but now it dont.
here a portion of my model User
protected $fillable = [
'prenom', 'nom', 'email','photo_path','password',
];
here my validation function :
protected function validator(array $data)
{
return Validator::make($data, [
'prenom' => 'required|string|max:255',
'nom' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'photo_path' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:10000',
'password' => 'required|string|min:6|confirmed',
]);
}
here my create function :
protected function create(array $data)
{
dd($data);
$photoInput = request('photo_path');
$userPhotoPath='users';
$storagePhotoPath = Storage::disk('images')->put($userPhotoPath, $photoInput);
return User::create([
'prenom' => $data['prenom'],
'nom' => $data['nom'],
'email' => $data['email'],
'photo_path' => $storagePhotoPath,
'password' => Hash::make($data['password']),
]);
}
- POST request working ( return 302 ) but return back with input value
- Auth Route are declared in web.php
- Validation working well
but the php interpretor didnt get inside create function...
i just see in debugbar that information :
The given data was invalid./home/e7250/Laravel/ManageMyWorkLife/vendor/laravel/framework/src/Illuminate/Validation/Validator.php#306Illuminate\Validation\ValidationException
public function validate()
{
if ($this->fails()) {
throw new ValidationException($this);
}
$data = collect($this->getData())
but my validation working because i have error message near my InputTexte.
so i dont understand that error message ...
Do you have any clue ?
Well, you need to remove the dd(); function before you run something. Other wise it will end the execution of all other operations.
Check if your User Model has a constructor, if so remove it and check if the problem still accours. This fixed it for me.

ActiveDataProvider:"query" property must be instance of a class that implements the QueryInterface

i am using an self-defined func that encapsu findBySql() to return rows .but got the error showed in the title. but if i test to use self-defined func that encapsu find() ,it worked,why?
Here is my action:
public function actionList()
{
$model = new Loan();
$dataProvider = new ActiveDataProvider(
[
'query' => $model->findValid($_GET['type']),//error comes here
'pagination' => [
'pagesize' => '2',
],
]);
return $this->renderPartial('list', ['model' => $model, 'dataProvider' => $dataProvider]);
}
Here is the object loan's findxx function:
public function findValid($type=null)
{
if($type==null){
return static::findBySql("select * from loan where wmstat&1=1 and (wmstat>>2)&1=0")->all();
}else{
return static::findBySql("select * from loan where wmstat&1=1 and (wmstat>>2)&1=0 and origin="."'".$type."'")->all();
}
}
Futher more,can i change the bit operatin using find() and where() and achieve the same effect ?
The error is clear, query expects valid query instance, while you are passing results of query and not the query itself.
Remove ->all() calls in findValid() method and it should work.
P.S. I strongly recommend to refactor your code to better condition.
Official docs:
ActiveDataProvider $query
ActiveQuery
findBySql()
Here is one with basic code example; not using ->all()
$query = User::find();
$dataProvider = new ActiveDataProvider([
'pagination' => ['pageSize' =>5],
'query' => $query,
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);

ZF2 / doctrine ORM authentication different Entity

in my application (ZF2 / ORM) i have 3 Entities (with Single Table inheritance)
User
Owner extends User
Agent extends User
i want to make one single Authentication (Login) for the 3 Entity using
doctrine.authenticationservice.orm_default
module.config.php
//other doctrine config
'authentication' => array(
'orm_default' => array(
'object_manager' => 'Doctrine\ORM\EntityManager',
'identity_class' => 'Application\Entity\User',
'identity_property' => 'email',
'credential_property' => 'password',
'credential_callable' => function(User $user, $passwordGiven) {
return $user->getPassword() == md5($passwordGiven);
},
),
),
and the process of login
//LoginController.php
// ..data validation
$this->authService = $this->getServiceLocator()->get('doctrine.authenticationservice.orm_default');
$AuthAdapter = $this->authService->getAdapter();
$AuthAdapter->setIdentity($this->request->getPost('email'));
$AuthAdapter->setCredential(md5($this->request->getPost('password')));
$result = $this->authService->authenticate();
if($result->isValid()){
$identity = $result->getIdentity();
//continue
}
how can i do this process without caring about object type,
when i try to login with email of an Agent, i get this error
Catchable fatal error: Argument 1 passed to Application\Module::{closure}() must be an instance of User, instance of Application\Entity\Owner given
The error you mention is due to the type hint on:
function(User $user) {
Which leads me to believe that you have a missing namespace declaration in your config file; in which case you can either add it or use the FQCN.
function(\Application\Entity\User $user) {
Nevertheless, I don't think it's actually the problem. You can only define one 'identity_class' with doctrine authentication (which the adapter will use to load the entity from the entity manager). If you have multiple entity classes there is no way to have each of these tested with one adapter.
However, the configuration is really just creating a new authentication adapter, specifically DoctrineModule\Authentication\Adapter\ObjectRepository. One solution would be to create multiple ObjectRepository adapters, each with the correct configuration for the different entities and then loop through each of them while calling authenticate() on the Zend\Authentication\AuthenticationService.
For example :
public function methodUsedToAutheticate($username, $password)
{
// Assume we have an array of configured adapters in an array
foreach($adapters as $adapter) {
$adapter->setIdentity($username);
$adapter->setCredential($password);
// Authenticate using the new adapter
$result = $authService->authenticate($adapter);
if ($result->isValid()) {
// auth success
break;
}
}
return $result; // auth failed
}
As previously mentioned is the doctrine config will not allow for more than one adapter, so you would need to create them manually and remove your current configuration.
Another example
public function getServiceConfig()
{
return [
'factories' => [
'MyServiceThatDoesTheAuthetication' => function($sm) {
$service = new MyServiceThatDoesTheAuthetication();
// Assume some kind of api to add multiple adapters
$service->addAuthAdapter($sm->get('AuthAdapterUser'));
$service->addAuthAdapter($sm->get('AuthAdapterOwner'));
$service->addAuthAdapter($sm->get('AuthAdapterAgent'));
return $service;
},
'AuthAdapterAgent' => function($sm) {
return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
'object_manager' => $sm->get('ObjectManager'),
'identity_class' => 'Application\Entity\Agent',
'identity_property' => 'email',
'credential_property' => 'password'
));
},
'AuthAdapterOwner' => function($sm) {
return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
'object_manager' => $sm->get('ObjectManager'),
'identity_class' => 'Application\Entity\Owner',
'identity_property' => 'email',
'credential_property' => 'password'
));
},
// etc...
],
];
}
Hopefully this gives you some ideas as to what is required.
Lastly, if you would consider other modules, ZfcUser already has a 'chainable adapter' which actually does the above (but uses the event manager) so It might be worth taking a look at even if you don't use it.

SaaS application structure in YII using separate database

I need create a SaaS application structure in YII Framework using separate database, but the examples in the web are using a single database. Any information or handbook will be welcome.
Thanks
You can use a second DB by adding it to your main.php ex:
'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=database',
'emulatePrepare' => true,
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'schemaCachingDuration' => 3600,
'enableProfiling' => true,
),
'db2'=>array(
'connectionString' => 'mysql:host=localhost;dbname=database2',
'class'=>'CDbConnection',
'emulatePrepare' => true,
'username' => 'username',
'password' => 'password',
'charset' => 'utf8',
'schemaCachingDuration' => 3600,
'enableProfiling' => true,
),
Then you can set the getDbConnection() method inside the active records that are to use this second db. I would suggest making a parent class extending from CActiveRecord with this code and then extending that.
It should contain:
public static $db2;
public function getDbConnection()
{
if(self::$db2!==null)
return self::$db2;
else
{
self::$db2=Yii::app()->db2;
if(self::$db2 instanceof CDbConnection)
{
self::$db2->setActive(true);
return self::$db2;
}
else
throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
}
}

Get the CSRF token in test

I'm writing functional test and i need to make ajax post request. "The CSRF token is invalid. Please try to resubmit the form". How can i get the token in my functional test ?
$crawler = $this->client->request(
'POST',
$url,
array(
'element_add' => array(
'_token' => '????',
'name' => 'bla',
)
),
array(),
array('HTTP_X-Requested-With' => 'XMLHttpRequest')
);
CSRF token generator is normal symfony 2 service. You can get service and generate token yourself. For example:
$csrfToken = $client->getContainer()->get('form.csrf_provider')->generateCsrfToken('registration');
$crawler = $client->request('POST', '/ajax/register', array(
'fos_user_registration_form' => array(
'_token' => $csrfToken,
'username' => 'samplelogin',
'email' => 'sample#fake.pl',
'plainPassword' => array(
'first' => 'somepass',
'second' => 'somepass',
),
'name' => 'sampleuser',
'type' => 'DSWP',
),
));
The generateCsrfToken gets one important parameter intention which should be the same in the test and in the form otherwise it fails.
After a long search (i've found nothing in doc and on the net about how to retrieve csrf token) i found a way:
$extract = $this->crawler->filter('input[name="element_add[_token]"]')
->extract(array('value'));
$csrf_token = $extract[0];
Extract the token from response before make the request.
In symfony 3, in your WebTestCase, you need to get the CSRF token:
$csrfToken = $client->getContainer()->get('security.csrf.token_manager')->getToken($csrfTokenId);
To get the $csrfTokenId, the best way would be to force it in the options of your FormType ():
class TaskType extends AbstractType
{
// ...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'csrf_token_id' => 'task_item',
));
}
// ...
}
So in this case: $csrfTokenId = "task_item";. Or you you can try to use the default value, that would be the name of your form.
Then use it as a post parameter:
$client->request(
'POST',
'/url',
[
'formName' => [
'field' => 'value',
'field2' => 'value2',
'_token' => $csrfToken
]
]
);
Just in case someone stumble on this, in symfony 5 you get the token this way:
$client->getContainer()->get('security.csrf.token_manager')->getToken('token-id')->getValue();
where 'token-id' is the id that you used in the configureOptions method in your form type, which would look something like this:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
"data_class" => Foo::class,
"csrf_protection" => true,
"csrf_field_name" => "field_name", //form field name where token will be placed. If left empty, this will default to _token
"csrf_token_id" => "token-id", //This is the token id you must use to get the token value in your test
]);
}
Then you just put the token in the request as a normal field.