I will go straight to the point
I have these 2 simple controllers:
/**
* #Route("/controller1", name="controller1")
*/
public function controller1(UserVerification $verification)
{
$verification->setVerificationCode();
return $this->render('user_settings/settings.html.twig');
}
/**
* #Route("/controller2", name="controller2")
*/
public function controller2(UserVerification $verification)
{
$verificationCode = $verification->getVerificationCode();
return $this->render('user_settings/settings.html.twig', [
'verificationCode' => $verificationCode
]);
}
And these two methods in my UserVerification Service:
public function setVerificationCode(){
$this->verificationCode = rand(100000, 999999);
return $this;
}
public function getVerificationCode(): int
{
return $this->verificationCode;
}
My question is: Is that real to get verificationCode in controller2 which has been set in controller1? For now in that example above in controller1 when i use method getVerificationCode() it's successfully returning some random code, but of course in controller2 it's returning null. Is there a way to share service instance?
Thanks for any advice
Here is the point:
In Symfony , by default , services are shared , that mean the same instance is working for many request , if you want the contrary you can modify it in service declaration of your service like :
# config/services.yaml
services:
App\SomeNonSharedService:
shared: false
# ...
But , here , it's different , you function is returning a random value , so even you are using the same service instance , it's sure that you will not have the same result , so here you can do 2 thing :
1- save data into session in case this logic concerns user when is logged in :
2- save data into the dababase
For the two solutions , you have for exmaple to verify if the value already exist into session/DB , like for the first this , it's your service that occur the result , and in the sametime store the value samewhere , so the next request , it will receive data from where you sotre it .
here is an example if you are using Session :
# config/services.yaml
services:
App\Services\CodeService:
arguments:
- "#session"
ServiceCode :
<?php
namespace App\Services;
use Symfony\Component\HttpFoundation\Session\Session;
class CodeService
{
private $session;
public function __construct( Session $session)
{
$this->session = $session;
}
pulic function setVerificationId(){
if(isset(!$this->session->get('verificationCode'))){
$this->session->set('verificationCode', rand(100000, 999999));
}
return this->getVerificationId();
}
public function getVerificationId()
{
return $this->session->get('verificationCode');
}
}
This case is working only if you are using session , if not , do the
same thing using EntityManager to store data somewhere in database.
Hope that help you.
Related
I'm stuck on something, and it seems internet haven't had this problem (or i haven't got the right keyword to find the answer)
Keep in mind that I'm still learning Symfony 6 and I'm a bit by myself for now ... So I'm open if you tell me that everything I did is garbage.
I'm creating an application to export datas in excels for our customers.
I create a call on a database, with a specific SQL request to get my datas. Then i send the datas in a SpreadsheetService to create my spreadsheet and launch the download for the user.
<?php
namespace App\Service;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\StreamedResponse;
class SpreadsheetService {
public function export(string $title, $datas, $rsm) {
$streamedResponse = new StreamedResponse();
$streamedResponse->setCallback(function () use ($title, $datas, $rsm) {
// Generating SpreadSheet
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle($title);
// Generating First Row with column name
$sheet->fromArray($rsm->scalarMappings);
// Generating other rows with datas
$count = 2;
foreach ($datas as $data) {
$sheet->fromArray($data, null, 'A' . $count);
$count++;
}
// Write and send created spreadsheet
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
// This exit(); is required to prevent errors while opening the generated .xlsx
exit();
});
// Puting headers on response and sending it
$streamedResponse->setStatusCode(Response::HTTP_OK);
$streamedResponse->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$streamedResponse->headers->set('Content-Disposition', 'attachment; filename="' . $title . '.xlsx"');
$streamedResponse->send();
return;
}
So, this is working like a charm. BUT, my chief want it to be asynchronous.
After some research on Symfony 6 and async in Symfony, I happened to find something called symfony/messenger, which at first sounded like it was only for send messages (mail, chat, sms ...) but after some reading, sounded like the async library for Symfony 6.
So, i tried by following step by step to setup the async.
First, i created an ExportMessage.php
<?php
namespace App\Message;
class ExportMessage {
// I need a slug to know for which customer i want the export
private string $slug;
// I need this string to know if it is an export for their clients, or their candidats etc ... (Wanted to setup an enum, but failed trying for now ...)
private string $typeExport;
public function __construct(string $slug, string $typeExport) {
$this->slug = $slug;
$this->typeExport = $typeExport;
}
/**
* Get the value of slug
*/
public function getSlug() {
return $this->slug;
}
/**
* Get the value of typeExport
*/
public function getTypeExport() {
return $this->typeExport;
}
}
Then i created an ExportHandler.php that will do some work when i send an ExportMessage (They go together)
<?php
namespace App\MessageHandler;
use App\Message\ExportMessage;
use App\Service\ClientRequestService;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class ExportHandler implements MessageHandlerInterface {
private ClientRequestService $clientRequestService;
// clientRequestService is the service that send the sql request and then call the SpreadsheetService to create the excel file
public function __construct(ClientRequestService $clientRequestService) {
$this->clientRequestService = $clientRequestService;
}
public function __invoke(ExportMessage $message) {
return $this->clientRequestService->export($message->getSlug(), $message->getTypeExport());
}
}
Finally, in my Controller, I don't call clientRequestService->export anymore, i create a messageBus that will keep track of any messages i send, and will process them correctly (Something like that, I didn't understand every aspect of it for now I think)
class DashboardController extends AbstractController {
private MessageBusInterface $messageBus;
public function __construct([...], MessageBusInterface $messageBus) {
[...]
$this->messageBus = $messageBus;
}
[...]
#[Route('{slug}/export-candidats', name: 'app_export_candidats')]
public function exportCandidats(string $slug) {
$this->messageBus->dispatch(new ExportMessage($slug, 'candidats'));
// Not anymore --> $this->requestService->export($slug, 'candidats');
return $this->redirectToRoute('app_dashboard', ['slug' => $slug]);
}
[...]
And just for the sake of it, here's the clientRequestService.php in case
<?php
namespace App\Service;
use App\Service\MappingService;
use App\Service\SpreadsheetService;
use App\Factory\EntityManagerFactory;
use App\Repository\Istrator\DatabaseGroupRepository;
class ClientRequestService {
private $factory;
private $databaseGroupRepository;
private $mappingService;
private $spreadsheetService;
private $rootpath_sql_request;
public function __construct(EntityManagerFactory $factory, DatabaseGroupRepository $databaseGroupRepository, MappingService $mappingService, SpreadsheetService $spreadsheetService, string $rootpath_sql_request) {
$this->factory = $factory;
$this->databaseGroupRepository = $databaseGroupRepository;
$this->mappingService = $mappingService;
$this->spreadsheetService = $spreadsheetService;
$this->rootpath_sql_request = $rootpath_sql_request;
}
public function export(string $slug, $export) {
$databaseGroup = $this->databaseGroupRepository->findBySlug($slug);
$entityManager = $this->factory->createManager($databaseGroup->getIdDb());
switch ($export) {
case 'candidats':
$rsm = $this->mappingService->getMappingExportCandidats($entityManager);
$query = file_get_contents($this->rootpath_sql_request . "export_candidats.sql");
break;
case 'clients':
$rsm = $this->mappingService->getMappingExportClients($entityManager);
$query = file_get_contents($this->rootpath_sql_request . "export_clients.sql");
break;
case 'pieces_jointes':
$rsm = $this->mappingService->getMappingPiecesJointes($entityManager);
$query = file_get_contents($this->rootpath_sql_request . "export_noms_pj.sql");
break;
case 'notes_suivi':
$rsm = $this->mappingService->getMappingNotesSuivi($entityManager);
$query = file_get_contents($this->rootpath_sql_request . "export_notes_suivi.sql");
break;
default:
return;
}
$results = $entityManager->createNativeQuery($query, $rsm)->execute();
$this->spreadsheetService->export($export, $results, $rsm);
}
}
It seems to be okay, but this doesn't trigger the download ...
Can someone help me understand this problem ?
EDIT 1:
After some research, i found out that the Handler isn't even called.
I tried some thing :
In the messenger.yaml i defined my ExportMessage as async :
framework:
messenger:
failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
use_notify: true
check_delayed_interval: 60000
retry_strategy:
max_retries: 3
multiplier: 2
failed: 'doctrine://default?queue_name=failed'
# sync: 'sync://'
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Symfony\Component\Notifier\Message\ChatMessage: async
Symfony\Component\Notifier\Message\SmsMessage: async
// --------------- Here ----------------
App\Message\ExportMessage: async
And then in my services.yaml I defined my handler as a Service
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
App\MessageHandler\ExportHandler:
tags: [messenger.message_handler]
[...]
Maybe this can narrow down some problems. My handlers isn't called and i don't understand why.
My message is sent (It's created in the database)
| 30 | O:36:\"Symfony\\Component\\Messenger\\Envelope\":2:{s:44:\"\0Symfony\\Component\\Messenger\\Envelope\0stamps\";a:1:{s:46:\"Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\";a:1:{i:0;O:46:\"Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\":1:{s:55:\"\0Symfony\\Component\\Messenger\\Stamp\\BusNameStamp\0busName\";s:21:\"messenger.bus.default\";}}}s:45:\"\0Symfony\\Component\\Messenger\\Envelope\0message\";O:25:\"App\\Message\\ExportMessage\":2:{s:31:\"\0App\\Message\\ExportMessage\0slug\";s:4:\"toma\";s:37:\"\0App\\Message\\ExportMessage\0typeExport\";s:9:\"candidats\";}} | [] | default | 2022-04-26 14:36:53 | 2022-04-26 14:36:53 | NULL |
I continue to work on it.
EDIT 2 :
Ok, so I didn't understand how asynchrones buses worked in php, because I'm from Typescript, and asynchronous process in Typescript are really different compared to this.
I needed a consumers that will listen when there is a message pushed in the bus, and consume it, and send it to the handler...
The documentation explained that, but i didn't understand :
https://symfony.com/doc/current/the-fast-track/en/18-async.html#running-workers-in-the-background
So now, I can generate my excel file asynchronously. I just have to create something to watch for it to be created, and give a link to download it.
Hope this thread can help some people who, like me, didn't quite understand the bus mecanic.
So I have a complicated onboarding process that does several steps. I created a class that handles the process but I've added a few more steps and I'd like to refactor this into something a bit more manageable. I refactored to use Laravel's pipeline, but feel this may not be the best refactor due to the output needing to be modified before each step.
Here is an example before and after with some pseudo code.
before
class OnboardingClass {
public $user;
public $conversation;
public function create($firstName, $lastName, $email){
// Step 1
$user = User::create();
// Step 2
$conversation = Conversation::create(); // store information for new user + existing user
// Step 3
$conversation->messages()->create(); // store a message on the conversation
// Step 4
// Send api request to analytics
// Step 5
// Send api request to other service
return $this;
}
}
after
class OnboardingClass{
public $user;
public $conversation;
public function create($firstName, $lastName, $email){
$data = ['first_name' => $firstName, ...]; // form data
$pipeline = app(Pipeline::Class);
$pipeline->send($data)
->through([
CreateUser::class,
CreateNewUserConversation::class,
AddWelcomeMessageToConversation::class,
...
])->then(function($data){
// set all properties returned from last class in pipeline.
$this->user = $data['user'];
$this->conversation = $data['conversation'];
});
return $this;
}
}
Now within each class I modify the previous data and output a modified version something like this
class CreateUser implements Pipe {
public function handle($data, Closure $next) {
// do some stuff
$user = User::create():
return $next([
'user' => $user,
'other' => 'something else'
]);
}
}
In my controller I am simply calling the create method.
class someController() {
public function store($request){
$onboarding = app(OnboardingClass::class);
$onboarding->create('John', 'Doe', 'john#example.com');
}
}
So the first pipe receives the raw form fields and outputs what the second pipe needs to get the job done in its class, then the next class outputs the data required by the next class, so on and so forth. The data that comes into each pipe is not the same each time and you cannot modify the order.
Feels a bit weird and I'm sure there is a cleaner way to handle this.
Any design pattern I can utilize to clean this up a bit?
I think you could try using Laravel Service Provider, for example, you could build a login service provider; or Event & Listener, for example, you could build an listener for login and triggers a event to handle all the necessary logics. Can't really tell which one is the best since outcome is the same and it makes same amount of network requests, but it's more on personal preferences
I am using symfony 4.2 framework in which there is PHP controller with multiple actions. I have set below values in packages\config.yaml.
myDir: '/abc'
I have below controller with 2 actions as defined below.
//this works
public function uploadTestAction(Request $r_request)
{
$myDir = $r_request->request->get("myDir");
}
//this doesn't work
public function loadTestAction(Request $r_request)
{
$myDir = $r_request->request->get("myDir");
//$myDir = $r_request->query->get("myDir"); //this is also not working
}
Issue here is I am able to get the value in uploadTestAction but value is coming as null in uploadTestAction. I have tried using query as well but still not getting the correct value. Both request types are GET. What I am missing here or how can trace it ?
you should define it as parameter:
https://symfony.com/doc/current/service_container/parameters.html
final class XyController extends SymfonyController {
public function registerAction() {
$dir = $this->container->getParameter('dir');
}
}
I have an API written using Symfony2 that I'm trying to write post hoc tests for. One of the endpoints uses an email service to send a password reset email to the user. I'd like to mock out this service so that I can check that the right information is sent to the service, and also prevent an email from actually being sent.
Here's the route I'm trying to test:
/**
* #Route("/me/password/resets")
* #Method({"POST"})
*/
public function requestResetAction(Request $request)
{
$userRepository = $this->get('app.repository.user_repository');
$userPasswordResetRepository = $this->get('app.repository.user_password_reset_repository');
$emailService = $this->get('app.service.email_service');
$authenticationLimitsService = $this->get('app.service.authentication_limits_service');
$now = new \DateTime();
$requestParams = $this->getRequestParams($request);
if (empty($requestParams->username)) {
throw new BadRequestHttpException("username parameter is missing");
}
$user = $userRepository->findOneByUsername($requestParams->username);
if ($user) {
if ($authenticationLimitsService->isUserBanned($user, $now)) {
throw new BadRequestHttpException("User temporarily banned because of repeated authentication failures");
}
$userPasswordResetRepository->deleteAllForUser($user);
$reset = $userPasswordResetRepository->createForUser($user);
$userPasswordResetRepository->saveUserPasswordReset($reset);
$authenticationLimitsService->logUserAction($user, UserAuthenticationLog::ACTION_PASSWORD_RESET, $now);
$emailService->sendPasswordResetEmail($user, $reset);
}
// We return 201 Created for every request so that we don't accidently
// leak the existence of usernames
return $this->jsonResponse("Created", $code=201);
}
I then have an ApiTestCase class that extends the Symfony WebTestCase to provide helper methods. This class contains a setup method that tries to mock the email service:
class ApiTestCase extends WebTestCase {
public function setup() {
$this->client = static::createClient(array(
'environment' => 'test'
));
$mockEmailService = $this->getMockBuilder(EmailService::class)
->disableOriginalConstructor()
->getMock();
$this->mockEmailService = $mockEmailService;
}
And then in my actual test cases I'm trying to do something like this:
class CreatePasswordResetTest extends ApiTestCase {
public function testSendsEmail() {
$this->mockEmailService->expects($this->once())
->method('sendPasswordResetEmail');
$this->post(
"/me/password/resets",
array(),
array("username" => $this->user->getUsername())
);
}
}
So now the trick is to get the controller to use the mocked version of the email service. I have read about several different ways to achieve this, so far I've not had much luck.
Method 1: Use container->set()
See How to mock Symfony 2 service in a functional test?
In the setup() method tell the container what it should return when it's asked for the email service:
static::$kernel->getContainer()->set('app.service.email_service', $this->mockEmailService);
# or
$this->client->getContainer()->set('app.service.email_service', $this->mockEmailService);
This does not effect the controller at all. It still calls the original service. Some write ups I've seen mention that the mocked service is 'reset' after a single call. I'm not even seeing my first call mocked out so I'm not certain this issue is affecting me yet.
Is there another container I should be calling set on?
Or am I mocking out the service too late?
Method 2: AppTestKernel
See: http://blog.lyrixx.info/2013/04/12/symfony2-how-to-mock-services-during-functional-tests.html
See: Symfony2 phpunit functional test custom user authentication fails after redirect (session related)
This one pulls me out of my depth when it comes to PHP and Symfony2 stuff (I'm not really a PHP dev).
The goal seems to be to change some kind of foundation class of the website to allow my mock service to be injected very early in the request.
I have a new AppTestKernel:
<?php
// app/AppTestKernel.php
require_once __DIR__.'/AppKernel.php';
class AppTestKernel extends AppKernel
{
private $kernelModifier = null;
public function boot()
{
parent::boot();
if ($kernelModifier = $this->kernelModifier) {
$kernelModifier($this);
$this->kernelModifier = null;
};
}
public function setKernelModifier(\Closure $kernelModifier)
{
$this->kernelModifier = $kernelModifier;
// We force the kernel to shutdown to be sure the next request will boot it
$this->shutdown();
}
}
And a new method in my ApiTestCase:
// https://stackoverflow.com/a/19705215
protected static function getKernelClass(){
$dir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : static::getPhpUnitXmlDir();
$finder = new Finder();
$finder->name('*TestKernel.php')->depth(0)->in($dir);
$results = iterator_to_array($finder);
if (!count($results)) {
throw new \RuntimeException('Either set KERNEL_DIR in your phpunit.xml according to http://symfony.com/doc/current/book/testing.html#your-first-functional-test or override the WebTestCase::createKernel() method.');
}
$file = current($results);
$class = $file->getBasename('.php');
require_once $file;
return $class;
}
Then I alter my setup() to use the kernel modifier:
public function setup() {
...
$mockEmailService = $this->getMockBuilder(EmailService::class)
->disableOriginalConstructor()
->getMock();
static::$kernel->setKernelModifier(function($kernel) use ($mockEmailService) {
$kernel->getContainer()->set('app.service.email_service', $mockEmailService);
});
$this->mockEmailService = $mockEmailService;
}
This works! However I now can't access the container in my other tests when I'm trying to do something like this:
$c = $this->client->getKernel()->getContainer();
$repo = $c->get('app.repository.user_password_reset_repository');
$resets = $repo->findByUser($user);
The getContainer() method returns null.
Should I be using the container differently?
Do I need to inject the container into the new kernel? It extends the original kernel so I don't really know why/how it's any different when it comes to the container stuff.
Method 3: Replace the service in config_test.yml
See: Symfony/PHPUnit mock services
This method requires that I write a new service class that overrides the email service. Writing a fixed mock class like this seems less useful than a regular dynamic mock. How can I test that certain methods have been called with certain parameters?
Method 4: Setup everything inside the test
Going on #Matteo's suggestion I wrote a test that did this:
public function testSendsEmail() {
$mockEmailService = $this->getMockBuilder(EmailService::class)
->disableOriginalConstructor()
->getMock();
$mockEmailService->expects($this->once())
->method('sendPasswordResetEmail');
static::$kernel->getContainer()->set('app.service.email_service', $mockEmailService);
$this->client->getContainer()->set('app.service.email_service', $mockEmailService);
$this->post(
"/me/password/resets",
array(),
array("username" => $this->user->getUsername())
);
}
This test fails because the expected method sendPasswordResetEmail wasn't called:
There was 1 failure:
1) Tests\Integration\Api\MePassword\CreatePasswordResetTest::testSendsEmail
Expectation failed for method name is equal to <string:sendPasswordResetEmail> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
Thanks to Cered's advice I've managed to get something working that can test that the emails I expect to be sent actually are. I haven't been able to actually get the mocking to work so I'm a bit reluctant to mark this as "the" answer.
Here's a test that checks that an email is sent:
public function testSendsEmail() {
$this->client->enableProfiler();
$this->post(
"/me/password/resets",
array(),
array("username" => $this->user->getUsername())
);
$mailCollector = $this->client->getProfile()->getCollector('swiftmailer');
$this->assertEquals(1, $mailCollector->getMessageCount());
$collectedMessages = $mailCollector->getMessages();
$message = $collectedMessages[0];
$this->assertInstanceOf('Swift_Message', $message);
$this->assertEquals('Reset your password', $message->getSubject());
$this->assertEquals('info#example.com', key($message->getFrom()));
$this->assertEquals($this->user->getEmail(), key($message->getTo()));
$this->assertContains(
'This link is valid for 24 hours only.',
$message->getBody()
);
$resets = $this->getResets($this->user);
$this->assertContains(
$resets[0]->getToken(),
$message->getBody()
);
}
It works by enabling the Symfony profiler and inspecting the swiftmailer service. It's documented here: http://symfony.com/doc/current/email/testing.html
I am trying to follow a tutorial for Zend Auth and Zend Acl using 1.11 framework Link here!
I have setup the authentication successfully and am able to use the authentication for the controller::action pairs given in the Acl.php page. Firstly I would like to test two additional parameter on the users table that whether the user account is activated and if the user is banned by administrator before allowing access to the site. How do I implement that in this code.
Secondly I would like to know how to include all actions under one controller to a User authorization level. i.e. I have a masters controller which has numerous actions under it for various tables. Could you tell me how to restrict access to Masters controller all actions to admin role only. Without adding resources and allow resources for each action in Acl.php. Also please tell me if this logic can be extended to allow access over entire modules instead of just the controllers(by one add resource and allow resource)? If yes how?
Firstly I would like to test two additional parameter on the users
table that whether the user account is activated and if the user is
banned by administrator before allowing access to the site.
The tutorial code uses a vanilla version of Zend_Auth_Adapter_DbTable which uses a specific api for authentication. To make Zend_Auth work how you want it to is not very difficult but will require some thought as you'll need to implement Zend_Auth_Adapter_Interface. Sounds worse then it is, you only have to implement the authenticate() method. Here is an example of an auth adapter that can be used in place of Zend_Auth_Adapter_DbTable:
<?php
//some code truncated for length and relevance
class My_Auth_Adapter implements Zend_Auth_Adapter_Interface
{
protected $identity = null;
protected $credential = null;
protected $usersMapper = null;
public function __construct($username, $password, My_Model_Mapper_Abstract $userMapper = null)
{
if (!is_null($userMapper)) {
$this->setMapper($userMapper);
} else {
$this->usersMapper = new Users_Model_Mapper_User();
}
$this->setIdentity($username);
$this->setCredential($password);
}
/**
* #return \Zend_Auth_Result
*/
public function authenticate()
{
// Fetch user information according to username
$user = $this->getUserObject();
if (is_null($user)) {
return new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
$this->getIdentity(),
array('Invalid username')
);
}
// check whether or not the hash matches
$check = Password::comparePassword($this->getCredential(), $user->password);
if (!$check) {
return new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
$this->getIdentity(),
array('Incorrect password')
);
}
// Success!
return new Zend_Auth_Result(
Zend_Auth_Result::SUCCESS,
$this->getIdentity(),
array()
);
}
// public function setIdentity($userName)
// public function setCredential($password)
// public function setMapper($mapper)
/**
* #return object
*/
private function getUserObject()
{
return $this->getMapper()->findOneByColumn('username', $this->getIdentity());
}
/**
* #return object
*/
public function getUser()
{
$object = $this->getUserObject();
$array = array(
'id' => $object->id,
'username' => $object->username,
'role' => $object->getRoleId()
);
return (object) $array;
}
// public function getIdentity()
// public function getCredential()
// public function getMapper()
}
You can modify the auth adapter to do pretty much anything you need.
As far as your access list is concerned, the thing to remember is that you resources are defined by a string. In the case of this tutorial a resource is defined as:
$this->add(new Zend_Acl_Resource('error::error'));
where the string on the left side of the colon represents the controller and the string on the right side of the colon represents the action. it's this line in the acl plugin that tell's us what the resources are:
if(!$acl->isAllowed($user->role, $request->getControllerName() . '::' . $request->getActionName()))
you can change this definition of what your resources represent to anything that works for you.
It's very difficult to provide hard and fast rules on how to implement an ACL because it seems that every project needs something different.
Look around the web and you'll find several different implementations of a Zend Framework ACL, some of them can be very complex.
Here is one that might provide some more insight. http://codeutopia.net/blog/2009/02/06/zend_acl-part-1-misconceptions-and-simple-acls/
good luck